Bug 1274393 - Check the pattern syntax again when adding unicode flag to RegExp object in RegExp constructor. r=till
authorTooru Fujisawa <arai_a@mac.com>
Sun, 22 May 2016 00:42:10 +0900
changeset 298378 458743bb901f19cf830b7133a128d1ff561d7ef0
parent 298377 4f1a4d674b7487785d4d8153d9714bc329dbe8b1
child 298379 ac5e8c0b9ec28e485a10ba84e2627106ea87cc87
push id30281
push usercbook@mozilla.com
push dateTue, 24 May 2016 12:54:02 +0000
treeherdermozilla-central@829d3be6ba64 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1274393
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1274393 - Check the pattern syntax again when adding unicode flag to RegExp object in RegExp constructor. r=till
js/src/builtin/RegExp.cpp
js/src/tests/ecma_6/RegExp/constructor-regexp-unicode.js
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -166,16 +166,25 @@ js::ExecuteRegExpLegacy(JSContext* cx, R
         /* Forbid an array, as an optimization. */
         rval.setBoolean(true);
         return true;
     }
 
     return CreateRegExpMatchResult(cx, input, matches, rval);
 }
 
+static bool
+CheckPatternSyntax(JSContext* cx, HandleAtom pattern, RegExpFlag flags)
+{
+    CompileOptions options(cx);
+    frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
+    return irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern,
+                                        flags & UnicodeFlag);
+}
+
 enum RegExpSharedUse {
     UseRegExpShared,
     DontUseRegExpShared
 };
 
 /*
  * ES 2016 draft Mar 25, 2016 21.2.3.2.2.
  * Because this function only ever returns |obj| in the spec, provided by the
@@ -217,23 +226,18 @@ RegExpInitializeIgnoringLastIndex(JSCont
             return false;
 
         /* Steps 9-12. */
         obj->initIgnoringLastIndex(pattern, flags);
 
         obj->setShared(*re);
     } else {
         /* Steps 7-8. */
-        CompileOptions options(cx);
-        frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
-        if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern,
-                                          flags & UnicodeFlag))
-        {
+        if (!CheckPatternSyntax(cx, pattern, flags))
             return false;
-        }
 
         /* Steps 9-12. */
         obj->initIgnoringLastIndex(pattern, flags);
     }
 
     return true;
 }
 
@@ -414,40 +418,49 @@ js::regexp_construct(JSContext* cx, unsi
         RegExpFlag flags;
         {
             // Step 4.a.
             RegExpGuard g(cx);
             if (!RegExpToShared(cx, patternObj, &g))
                 return false;
             sourceAtom = g->getSource();
 
-            if (!args.hasDefined(1)) {
-                // Step 4.b.
-                flags = g->getFlags();
-            }
+            // Step 4.b.
+            // Get original flags in all cases, to compare with passed flags.
+            flags = g->getFlags();
         }
 
         // Step 7.
         RootedObject proto(cx);
         if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
             return false;
 
         Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
         if (!regexp)
             return false;
 
         // Step 8.
         if (args.hasDefined(1)) {
             // Step 4.c / 21.2.3.2.2 RegExpInitialize step 4.
-            flags = RegExpFlag(0);
+            RegExpFlag flagsArg = RegExpFlag(0);
             RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
             if (!flagStr)
                 return false;
-            if (!ParseRegExpFlags(cx, flagStr, &flags))
+            if (!ParseRegExpFlags(cx, flagStr, &flagsArg))
                 return false;
+
+            if (!(flags & UnicodeFlag) && flagsArg & UnicodeFlag) {
+                // Have to check syntax again when adding 'u' flag.
+
+                // ES 2017 draft rev 9b49a888e9dfe2667008a01b2754c3662059ae56
+                // 21.2.3.2.2 step 7.
+                if (!CheckPatternSyntax(cx, sourceAtom, flagsArg))
+                    return false;
+            }
+            flags = flagsArg;
         }
 
         regexp->initAndZeroLastIndex(sourceAtom, flags, cx);
 
         args.rval().setObject(*regexp);
         return true;
     }
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/constructor-regexp-unicode.js
@@ -0,0 +1,9 @@
+var BUGNUMBER = 1274393;
+var summary = "RegExp constructor should check the pattern syntax again when adding unicode flag.";
+
+print(BUGNUMBER + ": " + summary);
+
+assertThrowsInstanceOf(() => RegExp(/\-/, "u"), SyntaxError);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);