RAB: Integrate staging tests for the .subarray method (#4177)

* Import relevant files from #3888

* Adds resizableArrayBufferUtils.js to includes and removes its content from each test

* renamed tests to indicate the end argument is tested too

* Adds more tests for the 'end' argument of .subarray
This commit is contained in:
Ioanna M Dimitriou H 2024-08-16 00:13:34 +02:00 committed by GitHub
parent cb4a6c8074
commit 224c5c3cb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 470 additions and 0 deletions

View File

@ -0,0 +1,106 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.subarray
description: >
TypedArray.p.subarray behaves correctly on TypedArrays backed by resizable
buffers that are grown by argument coercion.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [0, 2, 4, 6, ...] << lengthTracking
// Growing a fixed length TA back in bounds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// Make `fixedLength` OOB.
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
const evil = {
valueOf: () => {
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
// The length computation is done before parameter conversion. At that
// point, the length is 0, since the TA is OOB.
assert.compareArray(ToNumbers(fixedLength.subarray(evil, 1)), []);
}
// As above but with the second parameter conversion growing the buffer.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
// Make `fixedLength` OOB.
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
const evil = {
valueOf: () => {
rab.resize(4 * ctor.BYTES_PER_ELEMENT);
return 1;
}
};
// The length computation is done before parameter conversion. At that
// point, the length is 0, since the TA is OOB.
assert.compareArray(ToNumbers(fixedLength.subarray(0, evil)), []);
}
// Growing + fixed-length TA. Growing won't affect anything.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const evil = {
valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(evil)), [
0,
2,
4,
6
]);
}
// As above but with the second parameter conversion growing the buffer.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const evil = {
valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 4;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(0, evil)), [
0,
2,
4,
6
]);
}
// Growing + length-tracking TA. The length computation is done with the
// original length.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab, 0);
const evil = {
valueOf: () => {
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.compareArray(
ToNumbers(lengthTracking.subarray(evil, lengthTracking.length)), [
0,
2,
4,
6
]);
}

View File

@ -0,0 +1,192 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.subarray
description: >
TypedArray.p.subarray behaves correctly on TypedArrays backed by resizable
buffers that are shrunk by argument coercion.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [0, 2, 4, 6, ...] << lengthTracking
// Fixed-length TA + first parameter conversion shrinks. The old length is
// used in the length computation, and the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.throws(RangeError, () => {
fixedLength.subarray(evil);
});
}
// Like the previous test, but now we construct a smaller subarray and it
// succeeds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(evil, 1)), [0]);
}
// As above but with the second parameter conversion shrinking the buffer.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 1;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(0,evil)), [0]);
}
// Fixed-length TA + second parameter conversion shrinks. The old length is
// used in the length computation, and the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 3;
}
};
assert.throws(RangeError, () => {
fixedLength.subarray(0, evil);
});
}
// Like the previous test, but now we construct a smaller subarray and it
// succeeds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 1;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(0, evil)), [0]);
}
// Shrinking + fixed-length TA, subarray construction succeeds even though the
// TA goes OOB.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(evil, 1)), [0]);
}
// As above but with the second parameter conversion shrinking the buffer.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const fixedLength = new ctor(rab, 0, 4);
const evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 1;
}
};
assert.compareArray(ToNumbers(fixedLength.subarray(0,evil)), [0]);
}
// Length-tracking TA + first parameter conversion shrinks. The old length is
// used in the length computation, and the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.throws(RangeError, () => {
lengthTracking.subarray(evil, lengthTracking.length);
});
}
// Like the previous test, but now we construct a smaller subarray and it
// succeeds.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.compareArray(ToNumbers(lengthTracking.subarray(evil, 1)), [0]);
}
// As above but with the second parameter conversion shrinking the buffer.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 1;
}
};
assert.compareArray(ToNumbers(lengthTracking.subarray(0,evil)), [0]);
}
// Length-tracking TA + first parameter conversion shrinks. The second
// parameter is negative -> the relative index is not recomputed, and the
// subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0;
}
};
assert.throws(RangeError, () => {
lengthTracking.subarray(evil, -1);
});
}
// Length-tracking TA + second parameter conversion shrinks. The second
// parameter is too large -> the subarray construction fails.
for (let ctor of ctors) {
const rab = CreateRabForTest(ctor);
const lengthTracking = new ctor(rab);
let evil = {
valueOf: () => {
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 3;
}
};
assert.throws(RangeError, () => {
lengthTracking.subarray(0, evil);
});
}

View File

@ -0,0 +1,172 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-%typedarray%.prototype.subarray
description: >
TypedArray.p.subarray behaves correctly on TypedArrays backed by resizable
buffers.
includes: [compareArray.js, resizableArrayBufferUtils.js]
features: [resizable-arraybuffer]
---*/
for (let ctor of ctors) {
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
const fixedLength = new ctor(rab, 0, 4);
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
const lengthTracking = new ctor(rab, 0);
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
// Write some data into the array.
const taWrite = new ctor(rab);
for (let i = 0; i < 4; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, ...] << lengthTracking
// [4, 6, ...] << lengthTrackingWithOffset
const fixedLengthSubFull = fixedLength.subarray(0);
assert.compareArray(ToNumbers(fixedLengthSubFull), [
0,
2,
4,
6
]);
const fixedLengthWithOffsetSubFull = fixedLengthWithOffset.subarray(0);
assert.compareArray(ToNumbers(fixedLengthWithOffsetSubFull), [
4,
6
]);
const lengthTrackingSubFull = lengthTracking.subarray(0);
assert.compareArray(ToNumbers(lengthTrackingSubFull), [
0,
2,
4,
6
]);
const lengthTrackingWithOffsetSubFull = lengthTrackingWithOffset.subarray(0);
assert.compareArray(ToNumbers(lengthTrackingWithOffsetSubFull), [
4,
6
]);
// Relative offsets
assert.compareArray(ToNumbers(fixedLength.subarray(-2)), [
4,
6
]);
assert.compareArray(ToNumbers(fixedLengthWithOffset.subarray(-1)), [6]);
assert.compareArray(ToNumbers(lengthTracking.subarray(-2)), [
4,
6
]);
assert.compareArray(ToNumbers(lengthTrackingWithOffset.subarray(-1)), [6]);
// Shrink so that fixed length TAs go out of bounds.
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
// Orig. array: [0, 2, 4]
// [0, 2, 4, ...] << lengthTracking
// [4, ...] << lengthTrackingWithOffset
// We can create subarrays of OOB arrays (which have length 0), as long as
// the new arrays are not OOB.
assert.compareArray(ToNumbers(fixedLength.subarray(0)), []);
assert.compareArray(ToNumbers(fixedLengthWithOffset.subarray(0)), []);
assert.compareArray(ToNumbers(lengthTracking.subarray(0)), [
0,
2,
4
]);
assert.compareArray(ToNumbers(lengthTrackingWithOffset.subarray(0)), [4]);
// Also the previously created subarrays are OOB.
assert.sameValue(fixedLengthSubFull.length, 0);
assert.sameValue(fixedLengthWithOffsetSubFull.length, 0);
// Relative offsets
assert.compareArray(ToNumbers(lengthTracking.subarray(-2)), [
2,
4
]);
assert.compareArray(ToNumbers(lengthTrackingWithOffset.subarray(-1)), [4]);
// Shrink so that the TAs with offset go out of bounds.
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
assert.compareArray(ToNumbers(fixedLength.subarray(0)), []);
assert.compareArray(ToNumbers(lengthTracking.subarray(0)), [0]);
// Even the 0-length subarray of fixedLengthWithOffset would be OOB ->
// this throws.
assert.throws(RangeError, () => {
fixedLengthWithOffset.subarray(0);
});
// Also the previously created subarrays are OOB.
assert.sameValue(fixedLengthSubFull.length, 0);
assert.sameValue(fixedLengthWithOffsetSubFull.length, 0);
assert.sameValue(lengthTrackingWithOffsetSubFull.length, 0);
// Shrink to zero.
rab.resize(0);
assert.compareArray(ToNumbers(fixedLength.subarray(0)), []);
assert.compareArray(ToNumbers(lengthTracking.subarray(0)), []);
assert.throws(RangeError, () => {
fixedLengthWithOffset.subarray(0);
});
assert.throws(RangeError, () => {
lengthTrackingWithOffset.subarray(0);
});
// Also the previously created subarrays are OOB.
assert.sameValue(fixedLengthSubFull.length, 0);
assert.sameValue(fixedLengthWithOffsetSubFull.length, 0);
assert.sameValue(lengthTrackingWithOffsetSubFull.length, 0);
// Grow so that all TAs are back in-bounds.
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
for (let i = 0; i < 6; ++i) {
WriteToTypedArray(taWrite, i, 2 * i);
}
// Orig. array: [0, 2, 4, 6, 8, 10]
// [0, 2, 4, 6] << fixedLength
// [4, 6] << fixedLengthWithOffset
// [0, 2, 4, 6, 8, 10, ...] << lengthTracking
// [4, 6, 8, 10, ...] << lengthTrackingWithOffset
assert.compareArray(ToNumbers(fixedLength.subarray(0)), [
0,
2,
4,
6
]);
assert.compareArray(ToNumbers(fixedLengthWithOffset.subarray(0)), [
4,
6
]);
assert.compareArray(ToNumbers(lengthTracking.subarray(0)), [
0,
2,
4,
6,
8,
10
]);
assert.compareArray(ToNumbers(lengthTrackingWithOffset.subarray(0)), [
4,
6,
8,
10
]);
// Also the previously created subarrays are no longer OOB.
assert.sameValue(fixedLengthSubFull.length, 4);
assert.sameValue(fixedLengthWithOffsetSubFull.length, 2);
// Subarrays of length-tracking TAs are also length-tracking.
assert.sameValue(lengthTrackingSubFull.length, 6);
assert.sameValue(lengthTrackingWithOffsetSubFull.length, 4);
}