Author: [email protected]
Date: Wed May 27 04:23:26 2009
New Revision: 2064

Modified:
    branches/bleeding_edge/src/jsregexp.cc
    branches/bleeding_edge/src/jsregexp.h
    branches/bleeding_edge/test/mjsunit/regexp.js

Log:
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


Modified: branches/bleeding_edge/src/jsregexp.cc
==============================================================================
--- branches/bleeding_edge/src/jsregexp.cc      (original)
+++ branches/bleeding_edge/src/jsregexp.cc      Wed May 27 04:23:26 2009
@@ -4189,6 +4189,11 @@


  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 @@
      that->MakeCaseIndependent();
    }
    EnsureAnalyzed(that->on_success());
-  that->CalculateOffsets();
+  if (!has_failed()) {
+    that->CalculateOffsets();
+  }
  }


  void Analysis::VisitAction(ActionNode* that) {
    RegExpNode* target = that->on_success();
    EnsureAnalyzed(target);
-  // 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());
+  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 @@
    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 @@
      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());
-  info->AddFromFollowing(that->loop_node()->info());
+  if (!has_failed()) {
+    info->AddFromFollowing(that->loop_node()->info());
+  }
  }


@@ -4435,6 +4448,10 @@
    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();


Modified: branches/bleeding_edge/src/jsregexp.h
==============================================================================
--- branches/bleeding_edge/src/jsregexp.h       (original)
+++ branches/bleeding_edge/src/jsregexp.h       Wed May 27 04:23:26 2009
@@ -1310,7 +1310,7 @@
  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 @@
  #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);
  };

Modified: branches/bleeding_edge/test/mjsunit/regexp.js
==============================================================================
--- branches/bleeding_edge/test/mjsunit/regexp.js       (original)
+++ branches/bleeding_edge/test/mjsunit/regexp.js       Wed May 27 04:23:26 2009
@@ -375,3 +375,16 @@

  // 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");
+}
+

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to