Commit a7a978415cc for nodejs
commit a7a978415cc690fc1f751800a2a8052d4d02f289
Author: Aviv Keller <me@aviv.sh>
Date: Thu Oct 1 22:56:48 2026 -0400
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: https://github.com/v8/v8/commit/c795f5948568dc7c5cce585928b9a6acb307ca82
PR-URL: https://github.com/nodejs/node/pull/66380
Reviewed-By: Richard Lau <richard.lau@ibm.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
diff --git a/common.gypi b/common.gypi
index ce50adc016e..841dc0288cd 100644
--- a/common.gypi
+++ b/common.gypi
@@ -44,7 +44,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.36',
+ 'v8_embedder_string': '-node.37',
##### V8 defaults for Node.js #####
diff --git a/deps/v8/src/builtins/typed-array-set.tq b/deps/v8/src/builtins/typed-array-set.tq
index 6fe170ede86..51562299edc 100644
--- a/deps/v8/src/builtins/typed-array-set.tq
+++ b/deps/v8/src/builtins/typed-array-set.tq
@@ -46,32 +46,61 @@ transitioning javascript builtin TypedArrayPrototypeSet(
}
try {
- // 5. Let targetOffset be ? ToInteger(offset).
- // 6. If targetOffset < 0, throw a RangeError exception.
- let targetOffsetOverflowed: bool = false;
+ let attachedTargetAndLength: ValidJSTypedArrayAndLength;
let targetOffset: uintptr = 0;
- if (arguments.length > 1) {
- const offsetArg = arguments[1];
- try {
- targetOffset = ToUintPtr(offsetArg)
- // On values less than zero throw RangeError immediately.
- otherwise OffsetOutOfBounds,
- // On UintPtr or SafeInteger range overflow throw RangeError after
- // performing observable steps to follow the spec.
- OffsetOverflow, OffsetOverflow;
- } label OffsetOverflow {
- targetOffsetOverflowed = true;
+ let targetOffsetOverflowed: bool = false;
+
+ // If the offset argument is not provided then the targetOffset is 0.
+ const offsetArg: JSAny =
+ arguments.length > 1 ? arguments[1] : SmiConstant(0);
+ typeswitch (offsetArg) {
+ case (offsetSmi: Smi): {
+ // 5. Let targetOffset be ? ToInteger(offset).
+ // 6. If targetOffset < 0, throw a RangeError exception.
+ if (offsetSmi < 0) goto OffsetOutOfBounds;
+ targetOffset = Unsigned(SmiUntag(offsetSmi));
+
+ // For Smi offsets, integer conversion has no side effects, so step 4
+ // (IsImmutableBuffer check) can be deferred and combined with steps 7-9
+ // in EnsureValidAndReadLength without observable differences.
+ // 4. If IsImmutableBuffer(target.[[ViewedArrayBuffer]]) is true, throw
+ // a TypeError exception.
+ // 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
+ // 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
+ // exception.
+ // 9. Let targetLength be target.[[ArrayLength]].
+ attachedTargetAndLength = EnsureValidAndReadLength(
+ target, TypedArrayAccessMode::kWrite) otherwise Fail;
+ }
+ case (offsetOther: JSAny): {
+ // 4. If IsImmutableBuffer(target.[[ViewedArrayBuffer]]) is true, throw
+ // a TypeError exception.
+ if (IsImmutableArrayBuffer(target.buffer)) deferred {
+ goto Fail;
+ }
+
+ // 5. Let targetOffset be ? ToInteger(offset).
+ // 6. If targetOffset < 0, throw a RangeError exception.
+ try {
+ targetOffset = ToUintPtr(offsetOther)
+ // On values less than zero throw RangeError immediately.
+ otherwise OffsetOutOfBounds,
+ // On UintPtr or SafeInteger range overflow throw RangeError after
+ // performing observable steps to follow the spec.
+ OffsetOverflow, OffsetOverflow;
+ } label OffsetOverflow {
+ targetOffsetOverflowed = true;
+ }
+
+ // 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
+ // 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
+ // exception.
+ // 9. Let targetLength be target.[[ArrayLength]].
+ attachedTargetAndLength = EnsureValidAndReadLength(
+ target, TypedArrayAccessMode::kWrite) otherwise Fail;
}
- } else {
- // If the offset argument is not provided then the targetOffset is 0.
}
- // 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
- // 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
- // exception.
- const attachedTargetAndLength = EnsureValidAndReadLength(
- target, TypedArrayAccessMode::kWrite) otherwise Fail;
-
const overloadedArg = arguments[0];
try {
// 1. Choose SetTypedArrayFromTypedArray or SetTypedArrayFromArrayLike
@@ -86,7 +115,7 @@ transitioning javascript builtin TypedArrayPrototypeSet(
// 5. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError
// exception.
const attachedSourceAndLength =
- EnsureValidAndReadLength(typedArray, TypedArrayAccessMode::kWrite)
+ EnsureValidAndReadLength(typedArray, TypedArrayAccessMode::kRead)
otherwise Fail;
TypedArrayPrototypeSetTypedArray(
attachedTargetAndLength, attachedSourceAndLength, targetOffset,
diff --git a/deps/v8/test/mjsunit/immutable-arraybuffer.js b/deps/v8/test/mjsunit/immutable-arraybuffer.js
index 1a4619d53c0..a76ce4f7e5b 100644
--- a/deps/v8/test/mjsunit/immutable-arraybuffer.js
+++ b/deps/v8/test/mjsunit/immutable-arraybuffer.js
@@ -564,3 +564,47 @@ if (this.Worker) {
assertEquals('OK', w.getMessage());
w.terminate();
}
+
+(function testTypedArraySetOrder() {
+ const ab = new ArrayBuffer(8);
+ const imm = ab.transferToImmutable();
+ const immTA = new Uint8Array(imm);
+
+ let offsetEvaluated = false;
+ const offset = {
+ valueOf() {
+ offsetEvaluated = true;
+ return 0;
+ }
+ };
+
+ let sourceRead = false;
+ const source = {
+ get length() {
+ sourceRead = true;
+ return 1;
+ },
+ get 0() {
+ sourceRead = true;
+ return 42;
+ }
+ };
+
+ // 1. Immutable target throws before offset conversion or source reading
+ assertThrows(() => immTA.set(source, offset), TypeError);
+ assertFalse(offsetEvaluated, "offset should not be evaluated for immutable target");
+ assertFalse(sourceRead, "source should not be read for immutable target");
+
+ // 2. Mutable target can read from immutable TypedArray source
+ const mutableTA = new Uint8Array(8);
+ assertDoesNotThrow(() => mutableTA.set(immTA));
+
+ // 3. Detached target evaluates offset before throwing TypeError
+ const detachedAb = new ArrayBuffer(8);
+ const detachedTA = new Uint8Array(detachedAb);
+ %ArrayBufferDetach(detachedAb);
+
+ offsetEvaluated = false;
+ assertThrows(() => detachedTA.set([1], offset), TypeError);
+ assertTrue(offsetEvaluated, "offset should be evaluated for detached target");
+})();