Bug 1342663 - Check for detached source buffer in TypedArray.prototype.slice. r=arai
authorAndré Bargull <andre.bargull@gmail.com>
Mon, 27 Feb 2017 12:02:50 -0800
changeset 394195 f2358cbc60563b6fa71fd52f5182843cf58e0340
parent 394194 4fd9849aaa21ff78550b1f5d6546aaa7bf99307d
child 394196 6bf5cd5c076bed47e23510ae33027f6ab6e204a2
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1342663
milestone54.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 1342663 - Check for detached source buffer in TypedArray.prototype.slice. r=arai
js/src/builtin/TypedArray.js
js/src/tests/ecma_6/TypedArray/slice-detached.js
js/src/tests/jstests.list
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -980,17 +980,17 @@ function TypedArraySlice(start, end) {
     // Step 1.
     var O = this;
 
     // Step 2.
     if (!IsObject(O) || !IsTypedArray(O)) {
         return callFunction(CallTypedArrayMethodIfWrapped, O, start, end, "TypedArraySlice");
     }
 
-    GetAttachedArrayBuffer(O);
+    var buffer = GetAttachedArrayBuffer(O);
 
     // Step 3.
     var len = TypedArrayLength(O);
 
     // Step 4.
     var relativeStart = ToInteger(start);
 
     // Step 5.
@@ -1007,27 +1007,42 @@ function TypedArraySlice(start, end) {
                 : std_Math_min(relativeEnd, len);
 
     // Step 8.
     var count = std_Math_max(final - k, 0);
 
     // Step 9.
     var A = TypedArraySpeciesCreateWithLength(O, count);
 
-    // Step 14.a.
-    var n = 0;
+    // Steps 10-13 (Not implemented, bug 1140152).
+
+    // Steps 14-15.
+    if (count > 0) {
+        // Step 14.a.
+        var n = 0;
 
-    // Step 14.b.
-    while (k < final) {
-        // Steps 14.b.i-v.
-        A[n++] = O[k++];
+        // Steps 14.b.ii, 15.b.
+        if (buffer === null) {
+            // A typed array previously using inline storage may acquire a
+            // buffer, so we must check with the source.
+            buffer = ViewedArrayBufferIfReified(O);
+        }
+
+        if (IsDetachedBuffer(buffer))
+            ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+
+        // Step 14.b.
+        while (k < final) {
+            // Steps 14.b.i-v.
+            A[n++] = O[k++];
+        }
+
+        // FIXME: Implement step 15 (bug 1140152).
     }
 
-    // FIXME: Implement step 15 (bug 1140152).
-
     // Step 16.
     return A;
 }
 
 // ES6 draft rev30 (2014/12/24) 22.2.3.25 %TypedArray%.prototype.some(callbackfn[, thisArg]).
 function TypedArraySome(callbackfn/*, thisArg*/) {
     // Steps 1-2.
     var O = this;
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedArray/slice-detached.js
@@ -0,0 +1,103 @@
+// Tests for detached ArrayBuffer checks in %TypedArray%.prototype.slice ( start, end ).
+
+function* createTypedArrays(lengths = [0, 1, 4, 4096]) {
+    // Test with eagerly created ArrayBuffer.
+    for (let length of lengths) {
+        let buffer = new ArrayBuffer(length * Int32Array.BYTES_PER_ELEMENT);
+        let typedArray = new Int32Array(buffer);
+
+        yield {typedArray, length, buffer() { return buffer; }};
+    }
+
+    // Test with lazily created ArrayBuffer.
+    for (let length of lengths) {
+        let typedArray = new Int32Array(length);
+
+        yield {typedArray, length, buffer() { return typedArray.buffer; }};
+    }
+}
+
+if (typeof detachArrayBuffer === "function") {
+    // ArrayBuffer is detached when entering slice().
+    for (let {typedArray, buffer} of createTypedArrays()) {
+        detachArrayBuffer(buffer());
+        assertThrowsInstanceOf(() => {
+            typedArray.slice(0);
+        }, TypeError, "ArrayBuffer is detached on function entry");
+    }
+
+    // ArrayBuffer is detached when computing ToInteger(start).
+    for (let {typedArray, length, buffer} of createTypedArrays()) {
+        let detached = false;
+        let start = {
+            valueOf() {
+                assertEq(detached, false);
+                detachArrayBuffer(buffer());
+                assertEq(detached, false);
+                detached = true;
+                return 0;
+            }
+        };
+
+        // Doesn't throw an error when no bytes are copied.
+        if (length === 0) {
+            typedArray.slice(start);
+        } else {
+            assertThrowsInstanceOf(() => {
+                typedArray.slice(start);
+            }, TypeError, "ArrayBuffer is detached in ToInteger(start)");
+        }
+        assertEq(detached, true, "detachArrayBuffer was called");
+    }
+
+    // ArrayBuffer is detached when computing ToInteger(end).
+    for (let {typedArray, length, buffer} of createTypedArrays()) {
+        let detached = false;
+        let end = {
+            valueOf() {
+                assertEq(detached, false);
+                detachArrayBuffer(buffer());
+                assertEq(detached, false);
+                detached = true;
+                return length;
+            }
+        };
+
+        // Doesn't throw an error when no bytes are copied.
+        if (length === 0) {
+            typedArray.slice(0, end);
+        } else {
+            assertThrowsInstanceOf(() => {
+                typedArray.slice(0, end);
+            }, TypeError, "ArrayBuffer is detached in ToInteger(end)");
+        }
+        assertEq(detached, true, "detachArrayBuffer was called");
+    }
+
+    // ArrayBuffer is detached in species constructor.
+    for (let {typedArray, length, buffer} of createTypedArrays()) {
+        let detached = false;
+        typedArray.constructor = {
+            [Symbol.species]: function(...args) {
+                assertEq(detached, false);
+                detachArrayBuffer(buffer());
+                assertEq(detached, false);
+                detached = true;
+                return new Int32Array(...args);
+            }
+        };
+
+        // Doesn't throw an error when no bytes are copied.
+        if (length === 0) {
+            typedArray.slice(0);
+        } else {
+            assertThrowsInstanceOf(() => {
+                typedArray.slice(0);
+            }, TypeError, "ArrayBuffer is detached in TypedArraySpeciesCreate(...)");
+        }
+        assertEq(detached, true, "detachArrayBuffer was called");
+    }
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -163,19 +163,16 @@ skip script test262/built-ins/global/glo
 skip script test262/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js
 skip script test262/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js
 skip script test262/built-ins/TypedArray/prototype/find/predicate-may-detach-buffer.js
 skip script test262/built-ins/TypedArray/prototype/findIndex/predicate-may-detach-buffer.js
 skip script test262/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js
 skip script test262/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js
 skip script test262/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js
 skip script test262/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js
-skip script test262/built-ins/TypedArray/prototype/slice/detached-buffer-custom-ctor-same-targettype.js
-skip script test262/built-ins/TypedArray/prototype/slice/detached-buffer-custom-ctor-other-targettype.js
-skip script test262/built-ins/TypedArray/prototype/slice/detached-buffer-get-ctor.js
 skip script test262/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js
 skip script test262/built-ins/TypedArrays/internals/DefineOwnProperty/detached-buffer-realm.js
 skip script test262/built-ins/TypedArrays/internals/DefineOwnProperty/detached-buffer.js
 skip script test262/built-ins/TypedArrays/internals/Get/detached-buffer-realm.js
 skip script test262/built-ins/TypedArrays/internals/Get/detached-buffer.js
 skip script test262/built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer-realm.js
 skip script test262/built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer.js
 skip script test262/built-ins/TypedArrays/internals/HasProperty/detached-buffer-realm.js