<rdar://problem/6924033> REGRESSION: Assertion failure due to forward references
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 May 2009 03:22:47 +0000 (03:22 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 May 2009 03:22:47 +0000 (03:22 +0000)
Reviewed by Gavin Barraclough.

Add a pattern type for forward references to ensure that we don't confuse the
quantifier alternatives assertion.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@44174 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/yarr/RegexCompiler.cpp
JavaScriptCore/yarr/RegexInterpreter.cpp
JavaScriptCore/yarr/RegexJIT.cpp
JavaScriptCore/yarr/RegexPattern.h
LayoutTests/ChangeLog
LayoutTests/fast/js/regexp-backreferences-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regexp-backreferences.html [new file with mode: 0644]
LayoutTests/fast/js/resources/regexp-backreferences.js [new file with mode: 0644]

index a94c818..33d53af 100644 (file)
@@ -1,3 +1,24 @@
+2009-05-26  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        <rdar://problem/6924033> REGRESSION: Assertion failure due to forward references
+
+        Add a pattern type for forward references to ensure that we don't confuse the
+        quantifier alternatives assertion.
+
+        * yarr/RegexCompiler.cpp:
+        (JSC::Yarr::RegexPatternConstructor::atomBackReference):
+        (JSC::Yarr::RegexPatternConstructor::setupAlternativeOffsets):
+        * yarr/RegexInterpreter.cpp:
+        (JSC::Yarr::ByteCompiler::emitDisjunction):
+        * yarr/RegexJIT.cpp:
+        (JSC::Yarr::RegexGenerator::generateTerm):
+        * yarr/RegexPattern.h:
+        (JSC::Yarr::PatternTerm::):
+        (JSC::Yarr::PatternTerm::PatternTerm):
+        (JSC::Yarr::PatternTerm::ForwardReference):
+
 2009-05-26  Gavin Barraclough  <barraclough@apple.com>
 
         Reviewed by Oliver Hunt.
index 03e1acb..c7b3c81 100644 (file)
@@ -471,8 +471,10 @@ public:
         ASSERT(subpatternId);
         m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId);
 
-        if (subpatternId > m_pattern.m_numSubpatterns)
+        if (subpatternId > m_pattern.m_numSubpatterns) {
+            m_alternative->m_terms.append(PatternTerm::ForwardReference());
             return;
+        }
 
         PatternAlternative* currentAlternative = m_alternative;
         ASSERT(currentAlternative);
@@ -482,8 +484,10 @@ public:
             PatternTerm& term = currentAlternative->lastTerm();
             ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
 
-            if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId))
+            if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) {
+                m_alternative->m_terms.append(PatternTerm::ForwardReference());
                 return;
+            }
         }
 
         m_alternative->m_terms.append(PatternTerm(subpatternId));
@@ -594,6 +598,9 @@ public:
                 alternative->m_hasFixedSize = false;
                 break;
 
+            case PatternTerm::TypeForwardReference:
+                break;
+
             case PatternTerm::TypePatternCharacter:
                 term.inputPosition = currentInputPosition;
                 if (term.quantityType != QuantifierFixedCount) {
index f31e553..b0aae65 100644 (file)
@@ -1555,6 +1555,9 @@ public:
 
                 case PatternTerm::TypeBackReference:
                     atomBackReference(term.subpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                        break;
+
+                case PatternTerm::TypeForwardReference:
                     break;
 
                 case PatternTerm::TypeParenthesesSubpattern: {
index f0241d1..d07e401 100644 (file)
@@ -1071,6 +1071,9 @@ class RegexGenerator : private MacroAssembler {
             m_generationFailed = true;
             break;
 
+        case PatternTerm::TypeForwardReference:
+            break;
+
         case PatternTerm::TypeParenthesesSubpattern:
             if ((term.quantityCount == 1) && !term.parentheses.isCopy)
                 generateParenthesesSingle(state);
index 2e821a9..fb1b0ab 100644 (file)
@@ -78,6 +78,7 @@ struct PatternTerm {
         TypePatternCharacter,
         TypeCharacterClass,
         TypeBackReference,
+        TypeForwardReference,
         TypeParenthesesSubpattern,
         TypeParentheticalAssertion,
     } type;
@@ -143,6 +144,11 @@ struct PatternTerm {
         quantityCount = 1;
     }
 
+    static PatternTerm ForwardReference()
+    {
+        return PatternTerm(TypeForwardReference);
+    }
+
     static PatternTerm BOL()
     {
         return PatternTerm(TypeAssertionBOL);
index 35c4001..93e42d2 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-26  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        <rdar://problem/6924033> REGRESSION: Assertion failure due to forward references
+
+        Add a few more test cases for invalid back references.
+
+        * fast/js/regexp-backreferences-expected.txt: Added.
+        * fast/js/regexp-backreferences.html: Added.
+        * fast/js/resources/regexp-backreferences.js: Added.
+
 2009-05-26  Adam Barth  <abarth@webkit.org>
 
         https://bugs.webkit.org/show_bug.cgi?id=26011
diff --git a/LayoutTests/fast/js/regexp-backreferences-expected.txt b/LayoutTests/fast/js/regexp-backreferences-expected.txt
new file mode 100644 (file)
index 0000000..146b66a
--- /dev/null
@@ -0,0 +1,19 @@
+Test to ensure correct behaviour when using backreferences in a RegExp
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS /(...)\1$/.test('abcabc') is true
+PASS /(...)\1$/.test('abcdef') is false
+PASS /(...)\2$/.test('abcabc') is false
+PASS /(...)\2$/.test('abc') is false
+PASS /\1(...)$/.test('abcabc') is true
+PASS /\1(...)$/.test('abcdef') is true
+PASS /\2(...)$/.test('abcabc') is false
+PASS /\2(...)$/.test('abc') is false
+PASS /\1?(...)$/.test('abc') is true
+PASS /\1?(...)$/.test('abc') is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regexp-backreferences.html b/LayoutTests/fast/js/regexp-backreferences.html
new file mode 100644 (file)
index 0000000..2da9af4
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="resources/regexp-backreferences.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/resources/regexp-backreferences.js b/LayoutTests/fast/js/resources/regexp-backreferences.js
new file mode 100644 (file)
index 0000000..f7a371b
--- /dev/null
@@ -0,0 +1,14 @@
+description("Test to ensure correct behaviour when using backreferences in a RegExp");
+
+shouldBeTrue("/(...)\\1$/.test('abcabc')");
+shouldBeFalse("/(...)\\1$/.test('abcdef')");
+shouldBeFalse("/(...)\\2$/.test('abcabc')");
+shouldBeFalse("/(...)\\2$/.test('abc')");
+shouldBeTrue("/\\1(...)$/.test('abcabc')");
+shouldBeTrue("/\\1(...)$/.test('abcdef')");
+shouldBeFalse("/\\2(...)$/.test('abcabc')");
+shouldBeFalse("/\\2(...)$/.test('abc')");
+shouldBeTrue("/\\1?(...)$/.test('abc')");
+shouldBeTrue("/\\1?(...)$/.test('abc')");
+
+var successfullyParsed = true;