summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/TypedArray/set-detached.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/tests/non262/TypedArray/set-detached.js265
1 files changed, 265 insertions, 0 deletions
diff --git a/js/src/tests/non262/TypedArray/set-detached.js b/js/src/tests/non262/TypedArray/set-detached.js
new file mode 100644
index 0000000000..4f9226c608
--- /dev/null
+++ b/js/src/tests/non262/TypedArray/set-detached.js
@@ -0,0 +1,265 @@
+// Tests for detached ArrayBuffer checks in %TypedArray%.prototype.set(array|typedArray, offset).
+
+function* createTypedArrays(lengths = [0, 1, 4, 4096]) {
+ for (let length of lengths) {
+ let buffer = new ArrayBuffer(length * Int32Array.BYTES_PER_ELEMENT);
+ let typedArray = new Int32Array(buffer);
+
+ yield {typedArray, buffer};
+ }
+}
+
+if (typeof detachArrayBuffer === "function") {
+ class ExpectedError extends Error {}
+
+ // No detached check on function entry.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ detachArrayBuffer(buffer);
+
+ assertThrowsInstanceOf(() => typedArray.set(null, {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ }), ExpectedError);
+ }
+
+ // Check for detached buffer after calling ToInteger(offset). Test with:
+ // - valid offset,
+ // - too large offset,
+ // - and negative offset.
+ for (let [offset, error] of [[0, TypeError], [1000000, TypeError], [-1, RangeError]]) {
+ for (let source of [[], [0], new Int32Array(0), new Int32Array(1)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return offset;
+ }
+ }), error);
+ }
+ }
+ }
+
+ // Tests when called with detached typed array as source.
+ for (let {typedArray} of createTypedArrays()) {
+ for (let {typedArray: source, buffer: sourceBuffer} of createTypedArrays()) {
+ detachArrayBuffer(sourceBuffer);
+
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ }), ExpectedError);
+ }
+ }
+
+ // Check when detaching source buffer in ToInteger(offset). Test with:
+ // - valid offset,
+ // - too large offset,
+ // - and negative offset.
+ for (let [offset, error] of [[0, TypeError], [1000000, TypeError], [-1, RangeError]]) {
+ for (let {typedArray} of createTypedArrays()) {
+ for (let {typedArray: source, buffer: sourceBuffer} of createTypedArrays()) {
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ detachArrayBuffer(sourceBuffer);
+ return offset;
+ }
+ }), error);
+ }
+ }
+ }
+
+ // Test when target and source use the same underlying buffer and
+ // ToInteger(offset) detaches the buffer. Test with:
+ // - same typed array,
+ // - different typed array, but same element type,
+ // - and different element type.
+ for (let src of [ta => ta, ta => new Int32Array(ta.buffer), ta => new Float32Array(ta.buffer)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = src(typedArray);
+ assertThrowsInstanceOf(() => typedArray.set(source, {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ }), TypeError);
+ }
+ }
+
+ // Test when Get(src, "length") detaches the buffer, but srcLength is 0.
+ // Also use different offsets to ensure bounds checks use the typed array's
+ // length value from before detaching the buffer.
+ for (let offset of [() => 0, ta => Math.min(1, ta.length), ta => Math.max(0, ta.length - 1)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ get length() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ };
+ typedArray.set(source, offset(typedArray));
+ }
+ }
+
+ // Test when ToLength(Get(src, "length")) detaches the buffer, but
+ // srcLength is 0. Also use different offsets to ensure bounds checks use
+ // the typed array's length value from before detaching the buffer.
+ for (let offset of [() => 0, ta => Math.min(1, ta.length), ta => Math.max(0, ta.length - 1)]) {
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 0;
+ }
+ }
+ };
+ typedArray.set(source, offset(typedArray));
+ }
+ }
+
+ // Test no TypeError is thrown when the typed array is detached and
+ // srcLength > 0.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ };
+ if (typedArray.length === 0) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ typedArray.set(source);
+ }
+ }
+
+ // Same as above, but with side-effect when executing Get(src, "0").
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ get 0() {
+ throw new ExpectedError();
+ },
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ };
+ let err = typedArray.length === 0 ? RangeError : ExpectedError;
+ assertThrowsInstanceOf(() => typedArray.set(source), err);
+ }
+
+ // Same as above, but with side-effect when executing ToNumber(Get(src, "0")).
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = {
+ get 0() {
+ return {
+ valueOf() {
+ throw new ExpectedError();
+ }
+ };
+ },
+ length: {
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ };
+ let err = typedArray.length === 0 ? RangeError : ExpectedError;
+ assertThrowsInstanceOf(() => typedArray.set(source), err);
+ }
+
+ // Side-effects when getting the source elements detach the buffer.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = Object.defineProperties([], {
+ 0: {
+ get() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }
+ });
+ if (typedArray.length === 0) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ typedArray.set(source);
+ }
+ }
+
+ // Side-effects when getting the source elements detach the buffer. Also
+ // ensure other elements are accessed.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let accessed = false;
+ let source = Object.defineProperties([], {
+ 0: {
+ get() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ },
+ 1: {
+ get() {
+ assertEq(accessed, false);
+ accessed = true;
+ return 2;
+ }
+ }
+ });
+ if (typedArray.length <= 1) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ assertEq(accessed, false);
+ typedArray.set(source);
+ assertEq(accessed, true);
+ }
+ }
+
+ // Side-effects when converting the source elements detach the buffer.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let source = [{
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }];
+ if (typedArray.length === 0) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ typedArray.set(source);
+ }
+ }
+
+ // Side-effects when converting the source elements detach the buffer. Also
+ // ensure other elements are accessed.
+ for (let {typedArray, buffer} of createTypedArrays()) {
+ let accessed = false;
+ let source = [{
+ valueOf() {
+ detachArrayBuffer(buffer);
+ return 1;
+ }
+ }, {
+ valueOf() {
+ assertEq(accessed, false);
+ accessed = true;
+ return 2;
+ }
+ }];
+ if (typedArray.length <= 1) {
+ assertThrowsInstanceOf(() => typedArray.set(source), RangeError);
+ } else {
+ assertEq(accessed, false);
+ typedArray.set(source);
+ assertEq(accessed, true);
+ }
+ }
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);