8d0404d80b
Previous version: https://chromium-review.googlesource.com/c/v8/v8/+/3259648 Fix 1: ValueSerializer <3 JSArrayBufferView Fix 2: set flags correctly when creating DataViews via the API Bug: v8:11111 Change-Id: I9cbfdaff29f97c7823eaa3d931689b363e1f4cf7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3297708 Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/main@{#78046}
435 lines
13 KiB
JavaScript
435 lines
13 KiB
JavaScript
// Copyright 2021 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Flags: --harmony-rab-gsab --allow-natives-syntax
|
|
|
|
"use strict";
|
|
|
|
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
|
|
|
(function DataViewPrototype() {
|
|
const rab = CreateResizableArrayBuffer(40, 80);
|
|
const ab = new ArrayBuffer(80);
|
|
|
|
const dvRab = new DataView(rab, 0, 3);
|
|
const dvAb = new DataView(ab, 0, 3);
|
|
assertEquals(dvRab.__proto__, dvAb.__proto__);
|
|
})();
|
|
|
|
(function DataViewByteLength() {
|
|
const rab = CreateResizableArrayBuffer(40, 80);
|
|
|
|
const dv = new DataView(rab, 0, 3);
|
|
assertEquals(rab, dv.buffer);
|
|
assertEquals(3, dv.byteLength);
|
|
|
|
const emptyDv = new DataView(rab, 0, 0);
|
|
assertEquals(rab, emptyDv.buffer);
|
|
assertEquals(0, emptyDv.byteLength);
|
|
|
|
const dvWithOffset = new DataView(rab, 2, 3);
|
|
assertEquals(rab, dvWithOffset.buffer);
|
|
assertEquals(3, dvWithOffset.byteLength);
|
|
|
|
const emptyDvWithOffset = new DataView(rab, 2, 0);
|
|
assertEquals(rab, emptyDvWithOffset.buffer);
|
|
assertEquals(0, emptyDvWithOffset.byteLength);
|
|
|
|
const lengthTracking = new DataView(rab);
|
|
assertEquals(rab, lengthTracking.buffer);
|
|
assertEquals(40, lengthTracking.byteLength);
|
|
|
|
const offset = 8;
|
|
const lengthTrackingWithOffset = new DataView(rab, offset);
|
|
assertEquals(rab, lengthTrackingWithOffset.buffer);
|
|
assertEquals(40 - offset, lengthTrackingWithOffset.byteLength);
|
|
|
|
const emptyLengthTrackingWithOffset = new DataView(rab, 40);
|
|
assertEquals(rab, emptyLengthTrackingWithOffset.buffer);
|
|
assertEquals(0, emptyLengthTrackingWithOffset.byteLength);
|
|
})();
|
|
|
|
(function ConstructInvalid() {
|
|
const rab = CreateResizableArrayBuffer(40, 80);
|
|
|
|
// Length too big.
|
|
assertThrows(() => { new DataView(rab, 0, 41); }, RangeError);
|
|
|
|
// Offset too close to the end.
|
|
assertThrows(() => { new DataView(rab, 39, 2); }, RangeError);
|
|
|
|
// Offset beyond end.
|
|
assertThrows(() => { new DataView(rab, 40, 1); }, RangeError);
|
|
})();
|
|
|
|
(function ConstructorParameterConversionShrinks() {
|
|
const rab = CreateResizableArrayBuffer(40, 80);
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
|
|
assertThrows(() => { new DataView(rab, evil, 20);}, RangeError);
|
|
})();
|
|
|
|
(function ConstructorParameterConversionGrows() {
|
|
const gsab = CreateResizableArrayBuffer(40, 80);
|
|
const evil = { valueOf: () => {
|
|
gsab.resize(50);
|
|
return 0;
|
|
}};
|
|
|
|
// Constructing will fail unless we take the new size into account.
|
|
const dv = new DataView(gsab, evil, 50);
|
|
assertEquals(50, dv.byteLength);
|
|
})();
|
|
|
|
(function OrdinaryCreateFromConstructorShrinks() {
|
|
{
|
|
const rab = CreateResizableArrayBuffer(16, 40);
|
|
const newTarget = function() {}.bind(null);
|
|
Object.defineProperty(newTarget, "prototype", {
|
|
get() {
|
|
rab.resize(8);
|
|
return DataView.prototype;
|
|
}
|
|
});
|
|
assertThrows(() => {Reflect.construct(DataView, [rab, 0, 16], newTarget); },
|
|
RangeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(16, 40);
|
|
const newTarget = function() {}.bind(null);
|
|
Object.defineProperty(newTarget, "prototype", {
|
|
get() {
|
|
rab.resize(6);
|
|
return DataView.prototype;
|
|
}
|
|
});
|
|
assertThrows(() => {Reflect.construct(DataView, [rab, 8, 2], newTarget); },
|
|
RangeError);
|
|
}
|
|
})();
|
|
|
|
(function DataViewByteLengthWhenResizedOutOfBounds1() {
|
|
const rab = CreateResizableArrayBuffer(16, 40);
|
|
|
|
const fixedLength = new DataView(rab, 0, 8);
|
|
const lengthTracking = new DataView(rab);
|
|
|
|
assertEquals(8, fixedLength.byteLength);
|
|
assertEquals(16, lengthTracking.byteLength);
|
|
|
|
assertEquals(0, fixedLength.byteOffset);
|
|
assertEquals(0, lengthTracking.byteOffset);
|
|
|
|
rab.resize(2);
|
|
|
|
assertThrows(() => { fixedLength.byteLength; }, TypeError);
|
|
assertEquals(2, lengthTracking.byteLength);
|
|
|
|
assertThrows(() => { fixedLength.byteOffset; }, TypeError);
|
|
assertEquals(0, lengthTracking.byteOffset);
|
|
|
|
rab.resize(8);
|
|
|
|
assertEquals(8, fixedLength.byteLength);
|
|
assertEquals(8, lengthTracking.byteLength);
|
|
|
|
assertEquals(0, fixedLength.byteOffset);
|
|
assertEquals(0, lengthTracking.byteOffset);
|
|
|
|
rab.resize(40);
|
|
|
|
assertEquals(8, fixedLength.byteLength);
|
|
assertEquals(40, lengthTracking.byteLength);
|
|
|
|
assertEquals(0, fixedLength.byteOffset);
|
|
assertEquals(0, lengthTracking.byteOffset);
|
|
|
|
rab.resize(0);
|
|
|
|
assertThrows(() => { fixedLength.byteLength; }, TypeError);
|
|
assertEquals(0, lengthTracking.byteLength);
|
|
|
|
assertThrows(() => { fixedLength.byteOffset; }, TypeError);
|
|
assertEquals(0, lengthTracking.byteOffset);
|
|
})();
|
|
|
|
// The previous test with offsets.
|
|
(function DataViewByteLengthWhenResizedOutOfBounds2() {
|
|
const rab = CreateResizableArrayBuffer(20, 40);
|
|
|
|
const fixedLengthWithOffset = new DataView(rab, 8, 8);
|
|
const lengthTrackingWithOffset = new DataView(rab, 8);
|
|
|
|
assertEquals(8, fixedLengthWithOffset.byteLength);
|
|
assertEquals(12, lengthTrackingWithOffset.byteLength);
|
|
|
|
assertEquals(8, fixedLengthWithOffset.byteOffset);
|
|
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
|
|
|
rab.resize(10);
|
|
|
|
assertThrows(() => { fixedLengthWithOffset.byteLength }, TypeError);
|
|
assertEquals(2, lengthTrackingWithOffset.byteLength);
|
|
|
|
assertThrows(() => { fixedLengthWithOffset.byteOffset }, TypeError);
|
|
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
|
|
|
rab.resize(16);
|
|
|
|
assertEquals(8, fixedLengthWithOffset.byteLength);
|
|
assertEquals(8, lengthTrackingWithOffset.byteLength);
|
|
|
|
assertEquals(8, fixedLengthWithOffset.byteOffset);
|
|
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
|
|
|
rab.resize(40);
|
|
|
|
assertEquals(8, fixedLengthWithOffset.byteLength);
|
|
assertEquals(32, lengthTrackingWithOffset.byteLength);
|
|
|
|
assertEquals(8, fixedLengthWithOffset.byteOffset);
|
|
assertEquals(8, lengthTrackingWithOffset.byteOffset);
|
|
|
|
rab.resize(6);
|
|
|
|
assertThrows(() => { fixedLengthWithOffset.byteLength }, TypeError);
|
|
assertThrows(() => { lengthTrackingWithOffset.byteLength }, TypeError);
|
|
|
|
assertThrows(() => { fixedLengthWithOffset.byteOffset }, TypeError);
|
|
assertThrows(() => { lengthTrackingWithOffset.byteOffset }, TypeError);
|
|
})();
|
|
|
|
(function GetAndSet() {
|
|
const rab = CreateResizableArrayBuffer(64, 128);
|
|
const fixedLength = new DataView(rab, 0, 32);
|
|
const fixedLengthWithOffset = new DataView(rab, 2, 32);
|
|
const lengthTracking = new DataView(rab, 0);
|
|
const lengthTrackingWithOffset = new DataView(rab, 2);
|
|
|
|
testDataViewMethodsUpToSize(fixedLength, 32);
|
|
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
|
|
|
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
|
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTracking, 64);
|
|
assertAllDataViewMethodsThrow(lengthTracking, 65, RangeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 64 - 2);
|
|
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 64 - 2 + 1,
|
|
RangeError);
|
|
|
|
// Shrink so that fixed length TAs go out of bounds.
|
|
rab.resize(30);
|
|
|
|
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
|
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTracking, 30);
|
|
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 30 - 2);
|
|
|
|
// Shrink so that the TAs with offset go out of bounds.
|
|
rab.resize(1);
|
|
|
|
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
|
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
|
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 0, TypeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTracking, 1);
|
|
assertAllDataViewMethodsThrow(lengthTracking, 2, RangeError);
|
|
|
|
// Shrink to zero.
|
|
rab.resize(0);
|
|
|
|
assertAllDataViewMethodsThrow(fixedLength, 0, TypeError);
|
|
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 0, TypeError);
|
|
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 0, TypeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTracking, 0);
|
|
assertAllDataViewMethodsThrow(lengthTracking, 1, RangeError);
|
|
|
|
// Grow so that all views are back in-bounds.
|
|
rab.resize(34);
|
|
|
|
testDataViewMethodsUpToSize(fixedLength, 32);
|
|
assertAllDataViewMethodsThrow(fixedLength, 33, RangeError);
|
|
|
|
testDataViewMethodsUpToSize(fixedLengthWithOffset, 32);
|
|
assertAllDataViewMethodsThrow(fixedLengthWithOffset, 33, RangeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTracking, 34);
|
|
assertAllDataViewMethodsThrow(lengthTracking, 35, RangeError);
|
|
|
|
testDataViewMethodsUpToSize(lengthTrackingWithOffset, 34 - 2);
|
|
assertAllDataViewMethodsThrow(lengthTrackingWithOffset, 34 - 2 + 1,
|
|
RangeError);
|
|
})();
|
|
|
|
(function GetParameterConversionShrinks() {
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const fixedLength = new DataView(rab, 0, 64);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
assertThrows(() => { fixedLength.getUint8(evil); }, TypeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
assertThrows(() => { fixedLengthWithOffset.getUint8(evil); }, TypeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const lengthTracking = new DataView(rab);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 12;
|
|
}};
|
|
// The DataView is not out of bounds but the index is.
|
|
assertThrows(() => { lengthTracking.getUint8(evil); }, RangeError);
|
|
assertEquals(0, lengthTracking.getUint8(2));
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const lengthTrackingWithOffset = new DataView(rab, 2);
|
|
|
|
let evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 12;
|
|
}};
|
|
// The DataView is not out of bounds but the index is.
|
|
assertThrows(() => { lengthTrackingWithOffset.getUint8(evil); },
|
|
RangeError);
|
|
evil = { valueOf: () => {
|
|
rab.resize(0);
|
|
return 0;
|
|
}};
|
|
// Now the DataView is out of bounds.
|
|
assertThrows(() => { lengthTrackingWithOffset.getUint8(evil); }, TypeError);
|
|
}
|
|
})();
|
|
|
|
(function SetParameterConversionShrinks() {
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const fixedLength = new DataView(rab, 0, 64);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
assertThrows(() => { fixedLength.setUint8(evil, 0); }, TypeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
assertThrows(() => { fixedLengthWithOffset.setUint8(evil, 0); }, TypeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const lengthTracking = new DataView(rab);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 12;
|
|
}};
|
|
lengthTracking.setUint8(12, 0); // Does not throw.
|
|
// The DataView is not out of bounds but the index is.
|
|
assertThrows(() => { lengthTracking.setUint8(evil, 0); }, RangeError);
|
|
lengthTracking.setUint8(2, 0); // Does not throw.
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const lengthTrackingWithOffset = new DataView(rab, 2);
|
|
|
|
let evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 12;
|
|
}};
|
|
lengthTrackingWithOffset.setUint8(12, 0); // Does not throw.
|
|
// The DataView is not out of bounds but the index is.
|
|
assertThrows(() => { lengthTrackingWithOffset.setUint8(evil, 0); },
|
|
RangeError);
|
|
evil = { valueOf: () => {
|
|
rab.resize(0);
|
|
return 0;
|
|
}};
|
|
// Now the DataView is out of bounds.
|
|
assertThrows(() => { lengthTrackingWithOffset.setUint8(evil, 0); },
|
|
TypeError);
|
|
}
|
|
|
|
// The same tests as before, except now the "resizing" parameter is the second
|
|
// one, not the first one.
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const fixedLength = new DataView(rab, 0, 64);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
assertThrows(() => { fixedLength.setUint8(0, evil); }, TypeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const fixedLengthWithOffset = new DataView(rab, 2, 64);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
assertThrows(() => { fixedLengthWithOffset.setUint8(0, evil); }, TypeError);
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const lengthTracking = new DataView(rab);
|
|
|
|
const evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
lengthTracking.setUint8(12, 0); // Does not throw.
|
|
// The DataView is not out of bounds but the index is.
|
|
assertThrows(() => { lengthTracking.setUint8(12, evil); }, RangeError);
|
|
lengthTracking.setUint8(2, 0); // Does not throw.
|
|
}
|
|
{
|
|
const rab = CreateResizableArrayBuffer(640, 1280);
|
|
const lengthTrackingWithOffset = new DataView(rab, 2);
|
|
|
|
let evil = { valueOf: () => {
|
|
rab.resize(10);
|
|
return 0;
|
|
}};
|
|
// The DataView is not out of bounds but the index is.
|
|
assertThrows(() => { lengthTrackingWithOffset.setUint8(12, evil); },
|
|
RangeError);
|
|
evil = { valueOf: () => {
|
|
rab.resize(0);
|
|
return 0;
|
|
}};
|
|
// Now the DataView is out of bounds.
|
|
assertThrows(() => { lengthTrackingWithOffset.setUint8(0, evil); },
|
|
TypeError);
|
|
}
|
|
})();
|