Title: [231939] trunk
Revision
231939
Author
msab...@apple.com
Date
2018-05-17 19:59:31 -0700 (Thu, 17 May 2018)

Log Message

We don't throw SyntaxErrors for runtime generated regular expressions with errors
https://bugs.webkit.org/show_bug.cgi?id=185755

Reviewed by Keith Miller.

JSTests:

New regression test.

* stress/regexp-with-runtime-syntax-errors.js: Added.
(testThrowsSyntaxtError):
(fromExecWithBadUnicodeEscape):
(fromTestWithBadUnicodeProperty):
(fromSplitWithBadUnicodeIdentity):
(fromMatchWithBadUnicodeBackReference):
(fromReplaceWithBadUnicodeEscape):
(fromSearchWithBadUnicodeEscape):

Source/_javascript_Core:

Added a new helper that creates the correct exception to throw for each type of error when
compiling a RegExp.  Using that new helper, added missing checks for RegExp for the cases
where we create a new RegExp from an existing one.  Also refactored other places that we
throw SyntaxErrors after a failed RegExp compile to use the new helper.

* runtime/RegExp.h:
* runtime/RegExpConstructor.cpp:
(JSC::regExpCreate):
(JSC::constructRegExp):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncCompile):
* yarr/YarrErrorCode.cpp:
(JSC::Yarr::errorToThrow):
* yarr/YarrErrorCode.h:

LayoutTests:

Updated test and results from reporting a SyntaxError to an Out of memory error.

* js/script-tests/stack-overflow-regexp.js:
(shouldThrow.recursiveCall):
(shouldThrow):
(recursiveCall):
* js/stack-overflow-regexp-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (231938 => 231939)


--- trunk/JSTests/ChangeLog	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/JSTests/ChangeLog	2018-05-18 02:59:31 UTC (rev 231939)
@@ -1,3 +1,21 @@
+2018-05-17  Michael Saboff  <msab...@apple.com>
+
+        We don't throw SyntaxErrors for runtime generated regular expressions with errors
+        https://bugs.webkit.org/show_bug.cgi?id=185755
+
+        Reviewed by Keith Miller.
+
+        New regression test.
+
+        * stress/regexp-with-runtime-syntax-errors.js: Added.
+        (testThrowsSyntaxtError):
+        (fromExecWithBadUnicodeEscape):
+        (fromTestWithBadUnicodeProperty):
+        (fromSplitWithBadUnicodeIdentity):
+        (fromMatchWithBadUnicodeBackReference):
+        (fromReplaceWithBadUnicodeEscape):
+        (fromSearchWithBadUnicodeEscape):
+
 2018-05-16  Caio Lima  <ticaiol...@gmail.com>
 
         [ESNext][BigInt] Implement support for "/" operation

Added: trunk/JSTests/stress/regexp-with-runtime-syntax-errors.js (0 => 231939)


--- trunk/JSTests/stress/regexp-with-runtime-syntax-errors.js	                        (rev 0)
+++ trunk/JSTests/stress/regexp-with-runtime-syntax-errors.js	2018-05-18 02:59:31 UTC (rev 231939)
@@ -0,0 +1,66 @@
+// This test checks that malformed regular expressions compiled at runtime throw SyntaxErrors
+
+function testThrowsSyntaxtError(f)
+{
+    try {
+        f();
+    } catch (e) {
+        if (!e instanceof SyntaxError)
+            throw "Expected SynteaxError, but got: " + e;
+    }
+}
+
+function fromExecWithBadUnicodeEscape()
+{
+    let baseRE = /\u{123x}/;
+    let line = "abc";
+
+    (new RegExp(baseRE, "u")).exec(line);
+}
+
+function fromTestWithBadUnicodeProperty()
+{
+    let baseRE = /a|\p{Blah}/;
+    let line = "abc";
+
+    (new RegExp(baseRE, "u")).test(line);
+}
+
+function fromSplitWithBadUnicodeIdentity()
+{
+    let baseRE = /,|:|\-/;
+    let line = "abc:def-ghi";
+
+    let fields = line.split(new RegExp(baseRE, "u"));
+}
+
+function fromMatchWithBadUnicodeBackReference()
+{
+    let baseRE = /\123/;
+    let line = "xyz";
+
+    let fields = line.match(new RegExp(baseRE, "u"));
+}
+
+function fromReplaceWithBadUnicodeEscape()
+{
+    let baseRE = /\%/;
+    let line = "xyz";
+
+    let fields = line.replace(new RegExp(baseRE, "u"), "x");
+}
+
+function fromSearchWithBadUnicodeEscape()
+{
+    let baseRE = /\=/;
+    let line = "xyz";
+
+    let fields = line.search(new RegExp(baseRE, "u"));
+}
+
+testThrowsSyntaxtError(fromExecWithBadUnicodeEscape);
+testThrowsSyntaxtError(fromTestWithBadUnicodeProperty);
+testThrowsSyntaxtError(fromSplitWithBadUnicodeIdentity);
+testThrowsSyntaxtError(fromMatchWithBadUnicodeBackReference);
+testThrowsSyntaxtError(fromReplaceWithBadUnicodeEscape);
+testThrowsSyntaxtError(fromSearchWithBadUnicodeEscape);

Modified: trunk/LayoutTests/ChangeLog (231938 => 231939)


--- trunk/LayoutTests/ChangeLog	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/LayoutTests/ChangeLog	2018-05-18 02:59:31 UTC (rev 231939)
@@ -1,3 +1,18 @@
+2018-05-17  Michael Saboff  <msab...@apple.com>
+
+        We don't throw SyntaxErrors for runtime generated regular expressions with errors
+        https://bugs.webkit.org/show_bug.cgi?id=185755
+
+        Reviewed by Keith Miller.
+
+        Updated test and results from reporting a SyntaxError to an Out of memory error.
+
+        * js/script-tests/stack-overflow-regexp.js:
+        (shouldThrow.recursiveCall):
+        (shouldThrow):
+        (recursiveCall):
+        * js/stack-overflow-regexp-expected.txt:
+
 2018-05-17  Nan Wang  <n_w...@apple.com>
 
         AX: [macOS] Expose the primary screen height through AX API

Modified: trunk/LayoutTests/js/script-tests/stack-overflow-regexp.js (231938 => 231939)


--- trunk/LayoutTests/js/script-tests/stack-overflow-regexp.js	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/LayoutTests/js/script-tests/stack-overflow-regexp.js	2018-05-18 02:59:31 UTC (rev 231939)
@@ -1,13 +1,13 @@
 description('Test that we do not overflow the stack while handling regular expressions');
 
 // Base case.
-shouldThrow('new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")"))', '"SyntaxError: Invalid regular _expression_: too many nested disjunctions"');
+shouldThrow('new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")"))', '"Error: Out of memory: Invalid regular _expression_: too many nested disjunctions"');
 
 { // Verify that a deep JS stack does not help avoiding the error.
     function recursiveCall(depth) {
         if (!(depth % 10)) {
             debug("Creating RegExp at depth " + depth);
-            shouldThrow('new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")"))', '"SyntaxError: Invalid regular _expression_: too many nested disjunctions"');
+            shouldThrow('new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")"))', '"Error: Out of memory: Invalid regular _expression_: too many nested disjunctions"');
         }
         if (depth < 100) {
             recursiveCall(depth + 1);
@@ -25,5 +25,5 @@
     for (let i = 0; i < 50000; ++i) {
         _expression_ += ")(c))";
     }
-    shouldThrow('new RegExp(_expression_)', '"SyntaxError: Invalid regular _expression_: too many nested disjunctions"');
+    shouldThrow('new RegExp(_expression_)', '"Error: Out of memory: Invalid regular _expression_: too many nested disjunctions"');
 }

Modified: trunk/LayoutTests/js/stack-overflow-regexp-expected.txt (231938 => 231939)


--- trunk/LayoutTests/js/stack-overflow-regexp-expected.txt	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/LayoutTests/js/stack-overflow-regexp-expected.txt	2018-05-18 02:59:31 UTC (rev 231939)
@@ -3,30 +3,30 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 0
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 10
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 20
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 30
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 40
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 50
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 60
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 70
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 80
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 90
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 Creating RegExp at depth 100
-PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
-PASS new RegExp(_expression_) threw exception SyntaxError: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(Array(50000).join("(") + "a" + Array(50000).join(")")) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
+PASS new RegExp(_expression_) threw exception Error: Out of memory: Invalid regular _expression_: too many nested disjunctions.
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/Source/_javascript_Core/ChangeLog (231938 => 231939)


--- trunk/Source/_javascript_Core/ChangeLog	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-05-18 02:59:31 UTC (rev 231939)
@@ -1,3 +1,25 @@
+2018-05-17  Michael Saboff  <msab...@apple.com>
+
+        We don't throw SyntaxErrors for runtime generated regular expressions with errors
+        https://bugs.webkit.org/show_bug.cgi?id=185755
+
+        Reviewed by Keith Miller.
+
+        Added a new helper that creates the correct exception to throw for each type of error when
+        compiling a RegExp.  Using that new helper, added missing checks for RegExp for the cases
+        where we create a new RegExp from an existing one.  Also refactored other places that we
+        throw SyntaxErrors after a failed RegExp compile to use the new helper.
+
+        * runtime/RegExp.h:
+        * runtime/RegExpConstructor.cpp:
+        (JSC::regExpCreate):
+        (JSC::constructRegExp):
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncCompile):
+        * yarr/YarrErrorCode.cpp:
+        (JSC::Yarr::errorToThrow):
+        * yarr/YarrErrorCode.h:
+
 2018-05-17  Saam Barati  <sbar...@apple.com>
 
         Remove shrinkFootprint test from apitests since it's flaky

Modified: trunk/Source/_javascript_Core/runtime/Error.cpp (231938 => 231939)


--- trunk/Source/_javascript_Core/runtime/Error.cpp	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/runtime/Error.cpp	2018-05-18 02:59:31 UTC (rev 231939)
@@ -353,7 +353,15 @@
     return error;
 }
 
+JSObject* createOutOfMemoryError(ExecState* exec, const String& message)
+{
+    
+    auto* error = createError(exec, makeString("Out of memory: ", message), nullptr);
+    jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
+    return error;
+}
 
+
 const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
 
 void StrictModeTypeErrorFunction::destroy(JSCell* cell)

Modified: trunk/Source/_javascript_Core/runtime/Error.h (231938 => 231939)


--- trunk/Source/_javascript_Core/runtime/Error.h	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/runtime/Error.h	2018-05-18 02:59:31 UTC (rev 231939)
@@ -71,6 +71,7 @@
 JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*);
 JS_EXPORT_PRIVATE JSObject* createURIError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createOutOfMemoryError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* createOutOfMemoryError(ExecState*, const String&);
 
 JS_EXPORT_PRIVATE JSObject* createError(ExecState*, ErrorType, const String&);
 

Modified: trunk/Source/_javascript_Core/runtime/RegExp.h (231938 => 231939)


--- trunk/Source/_javascript_Core/runtime/RegExp.h	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/runtime/RegExp.h	2018-05-18 02:59:31 UTC (rev 231939)
@@ -62,6 +62,7 @@
 
     bool isValid() const { return !Yarr::hasError(m_constructionErrorCode) && m_flags != InvalidFlags; }
     const char* errorMessage() const { return Yarr::errorMessage(m_constructionErrorCode); }
+    JSObject* errorToThrow(ExecState* exec) { return Yarr::errorToThrow(exec, m_constructionErrorCode); }
 
     JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int>& ovector);
 

Modified: trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp (231938 => 231939)


--- trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/runtime/RegExpConstructor.cpp	2018-05-18 02:59:31 UTC (rev 231939)
@@ -243,7 +243,7 @@
 
     RegExp* regExp = RegExp::create(vm, pattern, flags);
     if (!regExp->isValid())
-        return throwException(exec, scope, createSyntaxError(exec, regExp->errorMessage()));
+        return throwException(exec, scope, regExp->errorToThrow(exec));
 
     Structure* structure = getRegExpStructure(exec, globalObject, newTarget);
     RETURN_IF_EXCEPTION(scope, nullptr);
@@ -281,6 +281,9 @@
             if (flags == InvalidFlags)
                 return nullptr;
             regExp = RegExp::create(vm, regExp->pattern(), flags);
+
+            if (!regExp->isValid())
+                return throwException(exec, scope, regExp->errorToThrow(exec));
         }
 
         return RegExpObject::create(vm, structure, regExp);

Modified: trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp (231938 => 231939)


--- trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/runtime/RegExpPrototype.cpp	2018-05-18 02:59:31 UTC (rev 231939)
@@ -174,7 +174,7 @@
     }
 
     if (!regExp->isValid())
-        return throwVMError(exec, scope, createSyntaxError(exec, regExp->errorMessage()));
+        return throwVMError(exec, scope, regExp->errorToThrow(exec));
 
     thisRegExp->setRegExp(vm, regExp);
     scope.release();

Modified: trunk/Source/_javascript_Core/yarr/YarrErrorCode.cpp (231938 => 231939)


--- trunk/Source/_javascript_Core/yarr/YarrErrorCode.cpp	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/yarr/YarrErrorCode.cpp	2018-05-18 02:59:31 UTC (rev 231939)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "YarrErrorCode.h"
 
+#include "Error.h"
+
 namespace JSC { namespace Yarr {
 
 const char* errorMessage(ErrorCode error)
@@ -58,4 +60,37 @@
     return errorMessages[static_cast<unsigned>(error)];
 }
 
+JSObject* errorToThrow(ExecState* exec, ErrorCode error)
+{
+    switch (error) {
+    case ErrorCode::NoError:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    case ErrorCode::PatternTooLarge:
+    case ErrorCode::QuantifierOutOfOrder:
+    case ErrorCode::QuantifierWithoutAtom:
+    case ErrorCode::QuantifierTooLarge:
+    case ErrorCode::MissingParentheses:
+    case ErrorCode::ParenthesesUnmatched:
+    case ErrorCode::ParenthesesTypeInvalid:
+    case ErrorCode::InvalidGroupName:
+    case ErrorCode::DuplicateGroupName:
+    case ErrorCode::CharacterClassUnmatched:
+    case ErrorCode::CharacterClassOutOfOrder:
+    case ErrorCode::EscapeUnterminated:
+    case ErrorCode::InvalidUnicodeEscape:
+    case ErrorCode::InvalidBackreference:
+    case ErrorCode::InvalidIdentityEscape:
+    case ErrorCode::InvalidUnicodePropertyExpression:
+    case ErrorCode::OffsetTooLarge:
+    case ErrorCode::InvalidRegularExpressionFlags:
+        return createSyntaxError(exec, errorMessage(error));
+    case ErrorCode::TooManyDisjunctions:
+        return createOutOfMemoryError(exec, errorMessage(error));
+    }
+
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
 } } // namespace JSC::Yarr

Modified: trunk/Source/_javascript_Core/yarr/YarrErrorCode.h (231938 => 231939)


--- trunk/Source/_javascript_Core/yarr/YarrErrorCode.h	2018-05-18 01:41:58 UTC (rev 231938)
+++ trunk/Source/_javascript_Core/yarr/YarrErrorCode.h	2018-05-18 02:59:31 UTC (rev 231939)
@@ -25,8 +25,13 @@
 
 #pragma once
 
-namespace JSC { namespace Yarr {
+namespace JSC {
 
+class ExecState;
+class JSObject;
+
+namespace Yarr {
+
 enum class ErrorCode : unsigned {
     NoError = 0,
     PatternTooLarge,
@@ -55,5 +60,6 @@
 {
     return errorCode != ErrorCode::NoError;
 }
+JS_EXPORT_PRIVATE JSObject* errorToThrow(ExecState*, ErrorCode);
 
 } } // namespace JSC::Yarr
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to