From 06c6da9be6e159000cf582f7a31173ea69984ed3 Mon Sep 17 00:00:00 2001 From: Doug Ilijev Date: Wed, 7 Feb 2018 03:07:43 -0800 Subject: [PATCH] deps: update ChakraCore to Microsoft/ChakraCore@a92d32a2d5 [1.8>1.9] [MERGE #4644 @dilijev] OS#15775563: Fix-up previous change. Explicitly allow RegExp identity escapes. Merge pull request #4644 from dilijev:fix_unicode_forbidden_escapes See #4637: Fix #4368: In unicode-mode RegExp, explicitly disallow invalid escapes. Fixes OS#15775563 Reviewed-By: chakrabot --- .../core/lib/Parser/RegexParser.cpp | 18 ++- .../test/Regex/unicode_forbidden_escapes.js | 111 +++++++++++++++--- 2 files changed, 113 insertions(+), 16 deletions(-) diff --git a/deps/chakrashim/core/lib/Parser/RegexParser.cpp b/deps/chakrashim/core/lib/Parser/RegexParser.cpp index 15011fc773e..4509c6ded0b 100644 --- a/deps/chakrashim/core/lib/Parser/RegexParser.cpp +++ b/deps/chakrashim/core/lib/Parser/RegexParser.cpp @@ -1750,11 +1750,27 @@ namespace UnifiedRegex } // Take to be identity escape if ill-formed as per Annex B break; + case '^': + case '$': + case '\\': + case '.': + case '*': + case '+': + case '?': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '|': + case '/': + break; // fall-through for identity escape default: if (this->unicodeFlagPresent) { // As per #sec-forbidden-extensions, if unicode flag is present, we must disallow any other escape. - Js::JavascriptError::ThrowSyntaxError(scriptContext, JSERR_RegExpInvalidEscape); + this->Fail(JSERR_RegExpInvalidEscape); // throw SyntaxError } // As per Annex B, allow anything other than newlines and above. Embedded 0 is ok break; diff --git a/deps/chakrashim/core/test/Regex/unicode_forbidden_escapes.js b/deps/chakrashim/core/test/Regex/unicode_forbidden_escapes.js index ef29be5e4b7..f983c417a95 100644 --- a/deps/chakrashim/core/test/Regex/unicode_forbidden_escapes.js +++ b/deps/chakrashim/core/test/Regex/unicode_forbidden_escapes.js @@ -5,29 +5,110 @@ WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js"); +let forbidden = [ + '\\p', + '\\P', + '\\a', + '\\A', + '\\e', + '\\E', + '\\y', + '\\Y', + '\\z', + '\\Z', +]; + +let identity = [ + "^", + "$", + "\\", + ".", + "*", + "+", + "?", + "(", + ")", + "[", + "]", + "{", + "}", + "|", + "/", +]; + +let pseudoIdentity = [ + ["f", "\f"], + ["n", "\n"], + ["r", "\r"], + ["t", "\t"], + ["v", "\v"], +] + var tests = [ { - name: "Unicode-mode RegExp Forbidden Escapes", + name: "Unicode-mode RegExp Forbidden Escapes (RegExp constructor)", body: function () { - let forbidden = [ - '\\p', - '\\P', - '\\a', - '\\A', - '\\e', - '\\E', - '\\y', - '\\Y', - '\\z', - '\\Z', - ]; - for (re of forbidden) { assert.throws(function () { new RegExp(re, 'u') }, SyntaxError, 'Invalid regular expression: invalid escape in unicode pattern'); assert.doesNotThrow(function () { new RegExp(re) }); } } - } + }, + { + name: "Unicode-mode RegExp Forbidden Escapes (literal)", + body: function () { + for (re of forbidden) { + assert.throws(function () { eval(`/${re}/u`); }, SyntaxError, 'Invalid regular expression: invalid escape in unicode pattern'); + assert.doesNotThrow(function () { eval(`/${re}/`); }, SyntaxError, 'Invalid regular expression: invalid escape in unicode pattern'); + } + } + }, + { + name: "Allow IdentityEscapes (RegExp constructor)", + body: function () { + for (c of identity) { + assert.doesNotThrow(function () { new RegExp(`\\${c}`, 'u') }); + assert.doesNotThrow(function () { new RegExp(`\\${c}`) }); + } + } + }, + { + name: "Allow IdentityEscapes (literal)", + body: function () { + for (c of identity) { + assert.doesNotThrow(function () { eval(`/\\${c}/u`); }); + assert.doesNotThrow(function () { eval(`/\\${c}/`); }); + } + } + }, + { + name: "Allow Pseudo-Identity Escapes (RegExpconstructor)", + body: function () { + for (test of pseudoIdentity) { + let c = test[0]; + let rendered = test[1]; + let re; + assert.doesNotThrow(function () { re = new RegExp(`\\${c}`, 'u') }); + assert.isTrue(re.test(rendered)); + assert.doesNotThrow(function () { re = new RegExp(`\\${c}`) }); + assert.isTrue(re.test(rendered)); + } + } + }, + { + name: "Allow Pseudo-Identity Escapes (literal)", + body: function () { + for (test of pseudoIdentity) { + let c = test[0]; + let rendered = test[1]; + let re; + assert.doesNotThrow(function () { re = eval(`/\\${c}/u`) }); + assert.isTrue(re.test(rendered)); + assert.doesNotThrow(function () { re = eval(`/\\${c}/`) }); + assert.isTrue(re.test(rendered)); + } + } + }, ]; testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });