Skip to content

Commit 798fcbb

Browse files
o-avivkeller
authored andcommitted
deps: V8: cherry-pick c795f5948568
Original commit message: [immutable-array-buffer] Fix check order in TypedArray.prototype.set According to the spec, TypedArray.prototype.set checks IsImmutableBuffer(target.[[ViewedArrayBuffer]]) before converting the offset argument to integer and before reading from the source object. Additionally, when setting from a TypedArray source, reading from an immutable source TypedArray is permitted, so the source array should be validated using TypedArrayAccessMode::kRead rather than kWrite. Drive-By: Add a fast case for Smi indices where the steps are not observable and we can fold all checks. TAG=agy CONV=94aa3be8-9990-41fe-a565-c62e3daa9a42 Bug: 450237486 Change-Id: I21790be90cde9a96ba7c1f573f034016d9c29850 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8252528 Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Igor Sheludko <ishell@chromium.org> Auto-Submit: Olivier Flückiger <olivf@chromium.org> Cr-Commit-Position: refs/heads/main@{#109366} Refs: v8/v8@c795f59
1 parent c570b67 commit 798fcbb

3 files changed

Lines changed: 97 additions & 24 deletions

File tree

‎deps/v8/include/v8-version.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#define V8_MAJOR_VERSION 14
1212
#define V8_MINOR_VERSION 6
1313
#define V8_BUILD_NUMBER 202
14-
#define V8_PATCH_LEVEL 34
14+
#define V8_PATCH_LEVEL 35
1515

1616
// Use 1 for candidates and 0 otherwise.
1717
// (Boolean macro values are not supported by all preprocessors.)

‎deps/v8/src/builtins/typed-array-set.tq‎

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,61 @@ transitioning javascript builtin TypedArrayPrototypeSet(
4646
}
4747

4848
try {
49-
// 5. Let targetOffset be ? ToInteger(offset).
50-
// 6. If targetOffset < 0, throw a RangeError exception.
51-
let targetOffsetOverflowed: bool = false;
49+
let attachedTargetAndLength: ValidJSTypedArrayAndLength;
5250
let targetOffset: uintptr = 0;
53-
if (arguments.length > 1) {
54-
const offsetArg = arguments[1];
55-
try {
56-
targetOffset = ToUintPtr(offsetArg)
57-
// On values less than zero throw RangeError immediately.
58-
otherwise OffsetOutOfBounds,
59-
// On UintPtr or SafeInteger range overflow throw RangeError after
60-
// performing observable steps to follow the spec.
61-
OffsetOverflow, OffsetOverflow;
62-
} label OffsetOverflow {
63-
targetOffsetOverflowed = true;
51+
let targetOffsetOverflowed: bool = false;
52+
53+
// If the offset argument is not provided then the targetOffset is 0.
54+
const offsetArg: JSAny =
55+
arguments.length > 1 ? arguments[1] : SmiConstant(0);
56+
typeswitch (offsetArg) {
57+
case (offsetSmi: Smi): {
58+
// 5. Let targetOffset be ? ToInteger(offset).
59+
// 6. If targetOffset < 0, throw a RangeError exception.
60+
if (offsetSmi < 0) goto OffsetOutOfBounds;
61+
targetOffset = Unsigned(SmiUntag(offsetSmi));
62+
63+
// For Smi offsets, integer conversion has no side effects, so step 4
64+
// (IsImmutableBuffer check) can be deferred and combined with steps 7-9
65+
// in EnsureValidAndReadLength without observable differences.
66+
// 4. If IsImmutableBuffer(target.[[ViewedArrayBuffer]]) is true, throw
67+
// a TypeError exception.
68+
// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
69+
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
70+
// exception.
71+
// 9. Let targetLength be target.[[ArrayLength]].
72+
attachedTargetAndLength = EnsureValidAndReadLength(
73+
target, TypedArrayAccessMode::kWrite) otherwise Fail;
74+
}
75+
case (offsetOther: JSAny): {
76+
// 4. If IsImmutableBuffer(target.[[ViewedArrayBuffer]]) is true, throw
77+
// a TypeError exception.
78+
if (IsImmutableArrayBuffer(target.buffer)) deferred {
79+
goto Fail;
80+
}
81+
82+
// 5. Let targetOffset be ? ToInteger(offset).
83+
// 6. If targetOffset < 0, throw a RangeError exception.
84+
try {
85+
targetOffset = ToUintPtr(offsetOther)
86+
// On values less than zero throw RangeError immediately.
87+
otherwise OffsetOutOfBounds,
88+
// On UintPtr or SafeInteger range overflow throw RangeError after
89+
// performing observable steps to follow the spec.
90+
OffsetOverflow, OffsetOverflow;
91+
} label OffsetOverflow {
92+
targetOffsetOverflowed = true;
93+
}
94+
95+
// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
96+
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
97+
// exception.
98+
// 9. Let targetLength be target.[[ArrayLength]].
99+
attachedTargetAndLength = EnsureValidAndReadLength(
100+
target, TypedArrayAccessMode::kWrite) otherwise Fail;
64101
}
65-
} else {
66-
// If the offset argument is not provided then the targetOffset is 0.
67102
}
68103

69-
// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
70-
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
71-
// exception.
72-
const attachedTargetAndLength = EnsureValidAndReadLength(
73-
target, TypedArrayAccessMode::kWrite) otherwise Fail;
74-
75104
const overloadedArg = arguments[0];
76105
try {
77106
// 1. Choose SetTypedArrayFromTypedArray or SetTypedArrayFromArrayLike
@@ -86,7 +115,7 @@ transitioning javascript builtin TypedArrayPrototypeSet(
86115
// 5. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError
87116
// exception.
88117
const attachedSourceAndLength =
89-
EnsureValidAndReadLength(typedArray, TypedArrayAccessMode::kWrite)
118+
EnsureValidAndReadLength(typedArray, TypedArrayAccessMode::kRead)
90119
otherwise Fail;
91120
TypedArrayPrototypeSetTypedArray(
92121
attachedTargetAndLength, attachedSourceAndLength, targetOffset,

‎deps/v8/test/mjsunit/immutable-arraybuffer.js‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,47 @@ if (this.Worker) {
564564
assertEquals('OK', w.getMessage());
565565
w.terminate();
566566
}
567+
568+
(function testTypedArraySetOrder() {
569+
const ab = new ArrayBuffer(8);
570+
const imm = ab.transferToImmutable();
571+
const immTA = new Uint8Array(imm);
572+
573+
let offsetEvaluated = false;
574+
const offset = {
575+
valueOf() {
576+
offsetEvaluated = true;
577+
return 0;
578+
}
579+
};
580+
581+
let sourceRead = false;
582+
const source = {
583+
get length() {
584+
sourceRead = true;
585+
return 1;
586+
},
587+
get 0() {
588+
sourceRead = true;
589+
return 42;
590+
}
591+
};
592+
593+
// 1. Immutable target throws before offset conversion or source reading
594+
assertThrows(() => immTA.set(source, offset), TypeError);
595+
assertFalse(offsetEvaluated, "offset should not be evaluated for immutable target");
596+
assertFalse(sourceRead, "source should not be read for immutable target");
597+
598+
// 2. Mutable target can read from immutable TypedArray source
599+
const mutableTA = new Uint8Array(8);
600+
assertDoesNotThrow(() => mutableTA.set(immTA));
601+
602+
// 3. Detached target evaluates offset before throwing TypeError
603+
const detachedAb = new ArrayBuffer(8);
604+
const detachedTA = new Uint8Array(detachedAb);
605+
%ArrayBufferDetach(detachedAb);
606+
607+
offsetEvaluated = false;
608+
assertThrows(() => detachedTA.set([1], offset), TypeError);
609+
assertTrue(offsetEvaluated, "offset should be evaluated for detached target");
610+
})();

0 commit comments

Comments
 (0)