Commit 2e37ebe1 authored by lrn@chromium.org's avatar lrn@chromium.org

Added stack overflow check for RegExp analysis phase.

A very long regexp graph can overflow the stack with recursive calls.

Review URL: http://codereview.chromium.org/113894


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2064 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 88635e40
......@@ -4189,6 +4189,11 @@ OutSet* DispatchTable::Get(uc16 value) {
void Analysis::EnsureAnalyzed(RegExpNode* that) {
StackLimitCheck check;
if (check.HasOverflowed()) {
fail("Stack overflow");
return;
}
if (that->info()->been_analyzed || that->info()->being_analyzed)
return;
that->info()->being_analyzed = true;
......@@ -4226,16 +4231,20 @@ void Analysis::VisitText(TextNode* that) {
that->MakeCaseIndependent();
}
EnsureAnalyzed(that->on_success());
if (!has_failed()) {
that->CalculateOffsets();
}
}
void Analysis::VisitAction(ActionNode* that) {
RegExpNode* target = that->on_success();
EnsureAnalyzed(target);
if (!has_failed()) {
// If the next node is interested in what it follows then this node
// has to be interested too so it can pass the information on.
that->info()->AddFromFollowing(target->info());
}
}
......@@ -4244,6 +4253,7 @@ void Analysis::VisitChoice(ChoiceNode* that) {
for (int i = 0; i < that->alternatives()->length(); i++) {
RegExpNode* node = that->alternatives()->at(i).node();
EnsureAnalyzed(node);
if (has_failed()) return;
// Anything the following nodes need to know has to be known by
// this node also, so it can pass it on.
info->AddFromFollowing(node->info());
......@@ -4257,13 +4267,16 @@ void Analysis::VisitLoopChoice(LoopChoiceNode* that) {
RegExpNode* node = that->alternatives()->at(i).node();
if (node != that->loop_node()) {
EnsureAnalyzed(node);
if (has_failed()) return;
info->AddFromFollowing(node->info());
}
}
// Check the loop last since it may need the value of this node
// to get a correct result.
EnsureAnalyzed(that->loop_node());
if (!has_failed()) {
info->AddFromFollowing(that->loop_node()->info());
}
}
......@@ -4435,6 +4448,10 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
data->node = node;
Analysis analysis(ignore_case);
analysis.EnsureAnalyzed(node);
if (analysis.has_failed()) {
const char* error_message = analysis.error_message();
return CompilationResult(error_message);
}
NodeInfo info = *node->info();
......
......@@ -1310,7 +1310,7 @@ FOR_EACH_NODE_TYPE(DECLARE_VISIT)
class Analysis: public NodeVisitor {
public:
explicit Analysis(bool ignore_case)
: ignore_case_(ignore_case) { }
: ignore_case_(ignore_case), error_message_(NULL) { }
void EnsureAnalyzed(RegExpNode* node);
#define DECLARE_VISIT(Type) \
......@@ -1319,8 +1319,17 @@ FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void VisitLoopChoice(LoopChoiceNode* that);
bool has_failed() { return error_message_ != NULL; }
const char* error_message() {
ASSERT(error_message_ != NULL);
return error_message_;
}
void fail(const char* error_message) {
error_message_ = error_message;
}
private:
bool ignore_case_;
const char* error_message_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis);
};
......
......@@ -375,3 +375,16 @@ assertFalse(/x([0-7]%%%x|[0-6]%%%y)/.test('x7%%%y'), 'qt8');
// Don't hang on this one.
/[^\xfe-\xff]*/.test("");
var long = "a";
for (var i = 0; i < 100000; i++) {
long = "a?" + long;
}
// Don't crash on this one, but maybe throw an exception.
try {
RegExp(long).exec("a");
} catch (e) {
assertTrue(String(e).indexOf("Stack overflow") >= 0, "overflow");
}
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