Fixed overflow bug in parsing of regexp repetitions.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 5 Feb 2009 12:55:20 +0000 (12:55 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 5 Feb 2009 12:55:20 +0000 (12:55 +0000)
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1231 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/parser.cc
test/mjsunit/regexp-pcre.js
test/mjsunit/regexp.js

index 97bb2f4..60172d5 100644 (file)
@@ -3938,6 +3938,9 @@ bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
 //   { DecimalDigits }
 //   { DecimalDigits , }
 //   { DecimalDigits , DecimalDigits }
+//
+// Returns true if parsing succeeds, and set the min_out and max_out
+// values. Values are truncated to RegExpTree::kInfinity if they overflow.
 bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
   ASSERT_EQ(current(), '{');
   int start = position();
@@ -3948,7 +3951,14 @@ bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
     return false;
   }
   while (IsDecimalDigit(current())) {
-    min = 10 * min + (current() - '0');
+    int next = current() - '0';
+    if (min > (RegExpTree::kInfinity - next) / 10) {
+      // Overflow. Skip past remaining decimal digits and return -1.
+      do { Advance(); } while (IsDecimalDigit(current()));
+      min = RegExpTree::kInfinity;
+      break;
+    }
+    min = 10 * min + next;
     Advance();
   }
   int max = 0;
@@ -3962,7 +3972,13 @@ bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
       Advance();
     } else {
       while (IsDecimalDigit(current())) {
-        max = 10 * max + (current() - '0');
+        int next = current() - '0';
+        if (max > (RegExpTree::kInfinity - next) / 10) {
+          do { Advance(); } while (IsDecimalDigit(current()));
+          max = RegExpTree::kInfinity;;
+          break;
+        }
+        max = 10 * max + next;
         Advance();
       }
       if (current() != '}') {
index 548656c..dcb1b32 100644 (file)
@@ -2110,7 +2110,8 @@ assertEquals(null, res[255].exec("ab\ncd", 463));
 assertEquals(null, res[255].exec("AbCd", 464));
 assertEquals(null, res[255].exec("** Failers", 465));
 assertEquals(null, res[255].exec("abcd", 466));
-assertThrows("var re = /(){2,4294967295}/;", 467);
+// We are compatible with JSC, and don't throw an exception in this case.
+// assertThrows("var re = /(){2,4294967295}/;", 467);
 assertEquals(null, res[255].exec("abcdefghijklAkB", 468));
 assertEquals(null, res[255].exec("abcdefghijklAkB", 469));
 assertEquals(null, res[255].exec("abcdefghijklAkB", 470));
index a54961a..e562df0 100644 (file)
@@ -304,11 +304,44 @@ for (var i = 0; i < 128; i++) {
 assertFalse(/f(o)$\1/.test('foo'), "backref detects at_end");
 
 // Check decimal escapes doesn't overflow.
-
+// (Note: \214 is interpreted as octal).
 assertEquals(/\2147483648/.exec("\x8c7483648"),
              ["\x8c7483648"],
              "Overflow decimal escape");
 
+
+// Check numbers in quantifiers doesn't overflow and doesn't throw on
+// too large numbers.
+assertFalse(/a{111111111111111111111111111111111111111111111}/.test('b'),
+            "overlarge1");
+assertFalse(/a{999999999999999999999999999999999999999999999}/.test('b'),
+            "overlarge2");
+assertFalse(/a{1,111111111111111111111111111111111111111111111}/.test('b'),
+            "overlarge3");
+assertFalse(/a{1,999999999999999999999999999999999999999999999}/.test('b'),
+            "overlarge4");
+assertFalse(/a{2147483648}/.test('b'),
+            "overlarge5");
+assertFalse(/a{21474836471}/.test('b'),
+            "overlarge6");
+assertFalse(/a{1,2147483648}/.test('b'),
+            "overlarge7");
+assertFalse(/a{1,21474836471}/.test('b'),
+            "overlarge8");
+assertFalse(/a{2147483648,2147483648}/.test('b'),
+            "overlarge9");
+assertFalse(/a{21474836471,21474836471}/.test('b'),
+            "overlarge10");
+assertFalse(/a{2147483647}/.test('b'),
+            "overlarge11");
+assertFalse(/a{1,2147483647}/.test('b'),
+            "overlarge12");
+assertTrue(/a{1,2147483647}/.test('a'),
+            "overlarge13");
+assertFalse(/a{2147483647,2147483647}/.test('a'),
+            "overlarge14");
+
+
 // Check that we don't read past the end of the string.
 assertFalse(/f/.test('b'));
 assertFalse(/[abc]f/.test('x'));