Bug 1263341 - Check lastIndex in non-global replace. r=till
authorTooru Fujisawa <arai_a@mac.com>
Sat, 09 Apr 2016 23:22:53 +0900
changeset 292477 7da431420a16cd42050678386bb26a8a4d240e67
parent 292476 b65a97f59b399841f15c2055496a905f04559b0a
child 292478 7d5f1e9ce04c9ec2edee19dd593f5951f7f3228e
push id74859
push userarai_a@mac.com
push dateSat, 09 Apr 2016 14:24:00 +0000
treeherdermozilla-inbound@7da431420a16 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1263341
milestone48.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 1263341 - Check lastIndex in non-global replace. r=till
js/src/builtin/RegExp.js
js/src/tests/ecma_6/RegExp/replace-sticky-lastIndex.js
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -475,17 +475,26 @@ function RegExpGlobalReplaceOpt(rx, S, l
 }
 
 // ES 2016 draft Mar 25, 2016 21.2.5.8 steps 11.a-16.
 // Optimized path for @@replace without global flag.
 function RegExpLocalReplaceOpt(rx, S, lengthS, replaceValue)
 {
     var sticky = !!rx.sticky;
 
-    var lastIndex = sticky ? rx.lastIndex : 0;
+    var lastIndex;
+    if (sticky) {
+        lastIndex = ToLength(rx.lastIndex);
+        if (lastIndex > lengthS) {
+            rx.lastIndex = 0;
+            return S;
+        }
+    } else {
+        lastIndex = 0;
+    }
 
     // Step 11.a.
     var result = RegExpMatcher(rx, S, lastIndex, sticky);
 
     // Step 11.b.
     if (result === null) {
         rx.lastIndex = 0;
         return S;
@@ -805,17 +814,17 @@ function RegExpBuiltinExec(R, S, forTest
 
     // Steps 8-9.
     var sticky = !!R.sticky;
 
     // Step 10.
     if (!global && !sticky) {
         lastIndex = 0;
     } else {
-        if (lastIndex < 0 || lastIndex > S.length) {
+        if (lastIndex > S.length) {
             // Steps 15.a.i-ii, 15.c.i.1-2.
             R.lastIndex = 0;
             return forTest ? false : null;
         }
     }
 
     if (forTest) {
         // Steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2.
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/replace-sticky-lastIndex.js
@@ -0,0 +1,23 @@
+var BUGNUMBER = 887016;
+var summary = "String.prototype.replace should do nothing if lastIndex is invalid for sticky RegExp";
+
+print(BUGNUMBER + ": " + summary);
+
+var re = /a/y;
+re.lastIndex = -1;
+assertEq("a".replace(re, "b"), "b");
+re.lastIndex = 0;
+assertEq("a".replace(re, "b"), "b");
+re.lastIndex = 1;
+assertEq("a".replace(re, "b"), "a");
+re.lastIndex = 2;
+assertEq("a".replace(re, "b"), "a");
+re.lastIndex = "foo";
+assertEq("a".replace(re, "b"), "b");
+re.lastIndex = "1";
+assertEq("a".replace(re, "b"), "a");
+re.lastIndex = {};
+assertEq("a".replace(re, "b"), "b");
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);