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 374245 f2358cbc60563b6fa71fd52f5182843cf58e0340
parent 374244 4fd9849aaa21ff78550b1f5d6546aaa7bf99307d
child 374246 6bf5cd5c076bed47e23510ae33027f6ab6e204a2
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1342663
milestone54.0a1
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