Crash: Array.prototype.slice() and .splice() can call fastSlice() after an array...
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 May 2016 21:42:44 +0000 (21:42 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 May 2016 21:42:44 +0000 (21:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=157322

Reviewed by Filip Pizlo.

Check to see if the source array has changed length before calling fastSlice().
If it has, take the slow path.

* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncSlice):
(JSC::arrayProtoFuncSplice):
* tests/stress/regress-157322.js: New test.

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/tests/stress/regress-157322.js [new file with mode: 0644]

index 03cd5e5..f2bb7ff 100644 (file)
@@ -1,3 +1,18 @@
+2016-05-03  Michael Saboff  <msaboff@apple.com>
+
+        Crash: Array.prototype.slice() and .splice() can call fastSlice() after an array is truncated
+        https://bugs.webkit.org/show_bug.cgi?id=157322
+
+        Reviewed by Filip Pizlo.
+
+        Check to see if the source array has changed length before calling fastSlice().
+        If it has, take the slow path.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncSlice):
+        (JSC::arrayProtoFuncSplice):
+        * tests/stress/regress-157322.js: New test.
+
 2016-05-03  Joseph Pecoraro  <pecoraro@apple.com>
 
         Eliminate PassRefPtr conversion from ConsoleObject
index cfdd7fc..08a6ec9 100644 (file)
@@ -863,7 +863,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
     if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception))
         return JSValue::encode(jsUndefined());
 
-    if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj))) {
+    if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj))) {
         if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin))
             return JSValue::encode(result);
     }
@@ -932,7 +932,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
         return JSValue::encode(jsUndefined());
 
     JSObject* result = nullptr;
-    if (speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj))
+    if (speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj))
         result = asArray(thisObj)->fastSlice(*exec, begin, deleteCount);
 
     if (!result) {
diff --git a/Source/JavaScriptCore/tests/stress/regress-157322.js b/Source/JavaScriptCore/tests/stress/regress-157322.js
new file mode 100644 (file)
index 0000000..05284d8
--- /dev/null
@@ -0,0 +1,43 @@
+// Regression test for https://bugs.webkit.org/show_bug.cgi?id=157322.  This test should not crash.
+
+let fromArray = [];
+let toArray = [];
+let dummyArray = [];
+let endObj1 = {
+    valueOf: function() {
+        let originalLength = fromArray.length;
+        fromArray.length = 1;
+
+        dummyArray = new Float64Array(1000);
+
+        return originalLength;
+    }
+};
+
+let endObj2 = {
+    valueOf: function() {
+        let originalLength = fromArray.length;
+        fromArray.length = 1;
+
+        dummyArray = new Float64Array(1000);
+
+        fromArray = [];
+        fromArray.length = originalLength;
+
+        return originalLength;
+    }
+};
+
+let initialArray = [];
+for (let i = 0; i < 8000; i++)
+        initialArray.push(i + 0.1);
+
+for (let loop = 0; loop < 1000; loop++) {
+    fromArray = initialArray.slice(0);
+
+    let endObj = (loop % 2 == 1) ? endObj1 : endObj2;
+
+    // These calls shouldn't crash
+    toArray = fromArray.slice(0, endObj);
+    toArray = fromArray.splice(0, endObj);
+}