Commit 358311e8 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Limit EatAtLeast recursion by a budget.

BUG=178790

Review URL: https://chromiumcodereview.appspot.com/12380026

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13788 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d7539af8
This diff is collapsed.
...@@ -582,9 +582,7 @@ class RegExpNode: public ZoneObject { ...@@ -582,9 +582,7 @@ class RegExpNode: public ZoneObject {
// used to indicate that we know we are not at the start of the input. In // used to indicate that we know we are not at the start of the input. In
// this case anchored branches will always fail and can be ignored when // this case anchored branches will always fail and can be ignored when
// determining how many characters are consumed on success. // determining how many characters are consumed on success.
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start) = 0;
int recursion_depth,
bool not_at_start) = 0;
// Emits some quick code that checks whether the preloaded characters match. // Emits some quick code that checks whether the preloaded characters match.
// Falls through on certain failure, jumps to the label on possible success. // Falls through on certain failure, jumps to the label on possible success.
// If the node cannot make a quick check it does nothing and returns false. // If the node cannot make a quick check it does nothing and returns false.
...@@ -616,9 +614,8 @@ class RegExpNode: public ZoneObject { ...@@ -616,9 +614,8 @@ class RegExpNode: public ZoneObject {
// implementation. TODO(erikcorry): This should share more code with // implementation. TODO(erikcorry): This should share more code with
// EatsAtLeast, GetQuickCheckDetails. The budget argument is used to limit // EatsAtLeast, GetQuickCheckDetails. The budget argument is used to limit
// the number of nodes we are willing to look at in order to create this data. // the number of nodes we are willing to look at in order to create this data.
static const int kFillInBMBudget = 200; static const int kRecursionBudget = 200;
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start) { bool not_at_start) {
...@@ -725,12 +722,10 @@ class SeqRegExpNode: public RegExpNode { ...@@ -725,12 +722,10 @@ class SeqRegExpNode: public RegExpNode {
void set_on_success(RegExpNode* node) { on_success_ = node; } void set_on_success(RegExpNode* node) { on_success_ = node; }
virtual RegExpNode* FilterASCII(int depth, bool ignore_case); virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start) { bool not_at_start) {
on_success_->FillInBMInfo( on_success_->FillInBMInfo(offset, budget - 1, bm, not_at_start);
offset, recursion_depth + 1, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm); if (offset == 0) set_bm_info(not_at_start, bm);
} }
...@@ -773,9 +768,7 @@ class ActionNode: public SeqRegExpNode { ...@@ -773,9 +768,7 @@ class ActionNode: public SeqRegExpNode {
RegExpNode* on_success); RegExpNode* on_success);
virtual void Accept(NodeVisitor* visitor); virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace); virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details, virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, RegExpCompiler* compiler,
int filled_in, int filled_in,
...@@ -784,7 +777,6 @@ class ActionNode: public SeqRegExpNode { ...@@ -784,7 +777,6 @@ class ActionNode: public SeqRegExpNode {
details, compiler, filled_in, not_at_start); details, compiler, filled_in, not_at_start);
} }
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start); bool not_at_start);
...@@ -843,9 +835,7 @@ class TextNode: public SeqRegExpNode { ...@@ -843,9 +835,7 @@ class TextNode: public SeqRegExpNode {
} }
virtual void Accept(NodeVisitor* visitor); virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace); virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details, virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, RegExpCompiler* compiler,
int characters_filled_in, int characters_filled_in,
...@@ -856,7 +846,6 @@ class TextNode: public SeqRegExpNode { ...@@ -856,7 +846,6 @@ class TextNode: public SeqRegExpNode {
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode( virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
RegExpCompiler* compiler); RegExpCompiler* compiler);
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start); bool not_at_start);
...@@ -911,15 +900,12 @@ class AssertionNode: public SeqRegExpNode { ...@@ -911,15 +900,12 @@ class AssertionNode: public SeqRegExpNode {
} }
virtual void Accept(NodeVisitor* visitor); virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace); virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details, virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, RegExpCompiler* compiler,
int filled_in, int filled_in,
bool not_at_start); bool not_at_start);
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start); bool not_at_start);
...@@ -960,7 +946,6 @@ class BackReferenceNode: public SeqRegExpNode { ...@@ -960,7 +946,6 @@ class BackReferenceNode: public SeqRegExpNode {
return; return;
} }
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start); bool not_at_start);
...@@ -989,7 +974,6 @@ class EndNode: public RegExpNode { ...@@ -989,7 +974,6 @@ class EndNode: public RegExpNode {
UNREACHABLE(); UNREACHABLE();
} }
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start) { bool not_at_start) {
...@@ -1075,11 +1059,9 @@ class ChoiceNode: public RegExpNode { ...@@ -1075,11 +1059,9 @@ class ChoiceNode: public RegExpNode {
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
DispatchTable* GetTable(bool ignore_case); DispatchTable* GetTable(bool ignore_case);
virtual void Emit(RegExpCompiler* compiler, Trace* trace); virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int recursion_depth,
bool not_at_start);
int EatsAtLeastHelper(int still_to_find, int EatsAtLeastHelper(int still_to_find,
int recursion_depth, int budget,
RegExpNode* ignore_this_node, RegExpNode* ignore_this_node,
bool not_at_start); bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details, virtual void GetQuickCheckDetails(QuickCheckDetails* details,
...@@ -1087,7 +1069,6 @@ class ChoiceNode: public RegExpNode { ...@@ -1087,7 +1069,6 @@ class ChoiceNode: public RegExpNode {
int characters_filled_in, int characters_filled_in,
bool not_at_start); bool not_at_start);
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start); bool not_at_start);
...@@ -1133,20 +1114,17 @@ class NegativeLookaheadChoiceNode: public ChoiceNode { ...@@ -1133,20 +1114,17 @@ class NegativeLookaheadChoiceNode: public ChoiceNode {
AddAlternative(this_must_fail); AddAlternative(this_must_fail);
AddAlternative(then_do_this); AddAlternative(then_do_this);
} }
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details, virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, RegExpCompiler* compiler,
int characters_filled_in, int characters_filled_in,
bool not_at_start); bool not_at_start);
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start) { bool not_at_start) {
alternatives_->at(1).node()->FillInBMInfo( alternatives_->at(1).node()->FillInBMInfo(
offset, recursion_depth + 1, budget - 1, bm, not_at_start); offset, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm); if (offset == 0) set_bm_info(not_at_start, bm);
} }
// For a negative lookahead we don't emit the quick check for the // For a negative lookahead we don't emit the quick check for the
...@@ -1169,15 +1147,12 @@ class LoopChoiceNode: public ChoiceNode { ...@@ -1169,15 +1147,12 @@ class LoopChoiceNode: public ChoiceNode {
void AddLoopAlternative(GuardedAlternative alt); void AddLoopAlternative(GuardedAlternative alt);
void AddContinueAlternative(GuardedAlternative alt); void AddContinueAlternative(GuardedAlternative alt);
virtual void Emit(RegExpCompiler* compiler, Trace* trace); virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find, virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details, virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, RegExpCompiler* compiler,
int characters_filled_in, int characters_filled_in,
bool not_at_start); bool not_at_start);
virtual void FillInBMInfo(int offset, virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget, int budget,
BoyerMooreLookahead* bm, BoyerMooreLookahead* bm,
bool not_at_start); bool not_at_start);
......
...@@ -820,7 +820,8 @@ function CallSiteGetMethodName() { ...@@ -820,7 +820,8 @@ function CallSiteGetMethodName() {
%_CallFunction(this.receiver, %_CallFunction(this.receiver,
ownName, ownName,
ObjectLookupSetter) === this.fun || ObjectLookupSetter) === this.fun ||
%GetDataProperty(this.receiver, ownName) === this.fun)) { (IS_OBJECT(this.receiver) &&
%GetDataProperty(this.receiver, ownName) === this.fun))) {
// To handle DontEnum properties we guess that the method has // To handle DontEnum properties we guess that the method has
// the same name as the function. // the same name as the function.
return ownName; return ownName;
...@@ -829,7 +830,8 @@ function CallSiteGetMethodName() { ...@@ -829,7 +830,8 @@ function CallSiteGetMethodName() {
for (var prop in this.receiver) { for (var prop in this.receiver) {
if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun || if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun ||
%_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun || %_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun ||
%GetDataProperty(this.receiver, prop) === this.fun) { (IS_OBJECT(this.receiver) &&
%GetDataProperty(this.receiver, prop) === this.fun)) {
// If we find more than one match bail out to avoid confusion. // If we find more than one match bail out to avoid confusion.
if (name) { if (name) {
return null; return null;
...@@ -883,10 +885,9 @@ function CallSiteGetPosition() { ...@@ -883,10 +885,9 @@ function CallSiteGetPosition() {
function CallSiteIsConstructor() { function CallSiteIsConstructor() {
var receiver = this.receiver; var receiver = this.receiver;
var constructor = receiver ? %GetDataProperty(receiver, "constructor") : null; var constructor =
if (!constructor) { IS_OBJECT(receiver) ? %GetDataProperty(receiver, "constructor") : null;
return false; if (!constructor) return false;
}
return this.fun === constructor; return this.fun === constructor;
} }
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Create a regexp in the form of a?a?...a? so that fully
// traversing the entire graph would be prohibitively expensive.
// This should not cause time out.
var r1 = "";
for (var i = 0; i < 1000; i++) {
r1 += "a?";
}
"test".match(RegExp(r1));
var r2 = "";
for (var i = 0; i < 100; i++) {
r2 += "(a?|b?|c?|d?|e?|f?|g?)";
}
"test".match(RegExp(r2));
// Create a regexp in the form of ((..(a)a..)a.
// Compiling it causes EatsAtLeast to reach the maximum
// recursion depth possible with a given budget.
// This should not cause a stack overflow.
var r3 = "a";
for (var i = 0; i < 1000; i++) {
r3 = "(" + r3 + ")a";
}
"test".match(RegExp(r3));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment