Skip to content

Commit a136367

Browse files
committed
fixup! lib: short-circuit WebIDL BufferSource SAB check
1 parent 5ee831f commit a136367

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

lib/internal/webidl.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const {
44
ArrayBufferIsView,
5-
ArrayBufferPrototype,
5+
ArrayBufferPrototypeGetByteLength,
66
ArrayPrototypePush,
77
ArrayPrototypeToSorted,
88
DataViewPrototypeGetBuffer,
@@ -34,7 +34,6 @@ const {
3434
const { kEmptyObject } = require('internal/util');
3535
const {
3636
isArrayBuffer,
37-
isSharedArrayBuffer,
3837
isTypedArray,
3938
} = require('internal/util/types');
4039

@@ -397,13 +396,17 @@ function getViewedArrayBuffer(V) {
397396
TypedArrayPrototypeGetBuffer(V) : DataViewPrototypeGetBuffer(V);
398397
}
399398

400-
// Returns `true` if `buffer` is a `SharedArrayBuffer`. The prototype-chain
401-
// check is a cheap V8 builtin that fast-accepts every non-tampered
402-
// `ArrayBuffer`; only buffers whose prototype chain has been detached or
403-
// reassigned (and real SABs) fall through to the authoritative brand check.
399+
// Returns `true` if `buffer` is a `SharedArrayBuffer`. Uses a brand check via
400+
// the `ArrayBuffer.prototype.byteLength` getter, which succeeds only on real
401+
// (non-shared) ArrayBuffers and throws on SharedArrayBuffers — independent
402+
// of the receiver's prototype chain.
404403
function isSharedArrayBufferBacking(buffer) {
405-
return !ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, buffer) &&
406-
isSharedArrayBuffer(buffer);
404+
try {
405+
ArrayBufferPrototypeGetByteLength(buffer);
406+
return false;
407+
} catch {
408+
return true;
409+
}
407410
}
408411

409412
// https://webidl.spec.whatwg.org/#ArrayBufferView

test/parallel/test-internal-webidl-buffer-source.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ test('BufferSource rejects SAB-backed DataView', () => {
8484
);
8585
});
8686

87+
test('BufferSource rejects SAB view whose buffer prototype was reassigned', () => {
88+
const sab = new SharedArrayBuffer(4);
89+
Object.setPrototypeOf(sab, ArrayBuffer.prototype);
90+
const view = new Uint8Array(sab);
91+
assert.throws(
92+
() => converters.BufferSource(view),
93+
{ code: 'ERR_INVALID_ARG_TYPE' },
94+
);
95+
});
96+
8797
test('BufferSource accepts a detached ArrayBuffer', () => {
8898
const ab = new ArrayBuffer(8);
8999
structuredClone(ab, { transfer: [ab] });
@@ -169,6 +179,16 @@ test('ArrayBufferView rejects SAB-backed DataView', () => {
169179
);
170180
});
171181

182+
test('ArrayBufferView rejects SAB view whose buffer prototype was reassigned', () => {
183+
const sab = new SharedArrayBuffer(4);
184+
Object.setPrototypeOf(sab, ArrayBuffer.prototype);
185+
const view = new Uint8Array(sab);
186+
assert.throws(
187+
() => converters.ArrayBufferView(view),
188+
{ code: 'ERR_INVALID_ARG_TYPE' },
189+
);
190+
});
191+
172192
test('ArrayBufferView rejects objects with a forged @@toStringTag', () => {
173193
const fake = { [Symbol.toStringTag]: 'Uint8Array' };
174194
assert.throws(

0 commit comments

Comments
 (0)