Skip to content

Commit 04904eb

Browse files
authored
ffi: fix exportArrayBuffer type check
Use isArrayBuffer() instead of comparing Object.prototype.toString() output. The old check depended on Symbol.toStringTag, so a real ArrayBuffer with a custom tag was rejected, and a plain object tagged 'ArrayBuffer' passed and failed later in native code with a misleading error. Signed-off-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Assisted-by: claude:opus-5.5 PR-URL: #66455 Fixes: #66454 Reviewed-By: René <contact.9a5d6388@renegade334.me.uk> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 0a3c7f1 commit 04904eb

2 files changed

Lines changed: 11 additions & 2 deletions

File tree

‎lib/ffi.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const {
88
ObjectFreeze,
99
ObjectGetOwnPropertyDescriptor,
1010
ObjectKeys,
11-
ObjectPrototypeToString,
1211
ReflectConstruct,
1312
SafeWeakMap,
1413
SafeWeakRef,
@@ -18,6 +17,7 @@ const {
1817
const { Buffer } = require('buffer');
1918
const { emitExperimentalWarning } = require('internal/util');
2019
const {
20+
isArrayBuffer,
2121
isDataView,
2222
isArrayBufferView,
2323
isSharedArrayBuffer,
@@ -311,7 +311,7 @@ function exportBuffer(source, data, len) {
311311
function exportArrayBuffer(source, data, len) {
312312
checkFFIPermission();
313313

314-
if (ObjectPrototypeToString(source) !== '[object ArrayBuffer]') {
314+
if (!isArrayBuffer(source)) {
315315
throw new ERR_INVALID_ARG_TYPE('arrayBuffer', 'ArrayBuffer', source);
316316
}
317317

‎test/ffi/test-ffi-memory.js‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ test('ffi exportString and exportBuffer copy data into native memory', () => {
238238
ffi.exportArrayBuffer(arrayBuffer, arrayBufferPtr, 4);
239239
assert.deepStrictEqual([...ffi.toBuffer(arrayBufferPtr, 4)], [8, 9, 10, 11]);
240240

241+
const taggedArrayBuffer = new Uint8Array([12, 13, 14, 15]).buffer;
242+
Object.defineProperty(taggedArrayBuffer, Symbol.toStringTag, { value: 'Custom' });
243+
ffi.exportArrayBuffer(taggedArrayBuffer, arrayBufferPtr, 4);
244+
assert.deepStrictEqual([...ffi.toBuffer(arrayBufferPtr, 4)], [12, 13, 14, 15]);
245+
241246
const viewPtr = alloc(8);
242247
const viewSource = new Uint16Array([0x0102, 0x0304, 0x0506]);
243248
const middleBytes = new Uint8Array(viewSource.buffer, 2, 2);
@@ -318,6 +323,10 @@ test('ffi validates memory access arguments', () => {
318323
assert.throws(() => ffi.exportBuffer(Buffer.from([1]), ptr, -1), { code: 'ERR_OUT_OF_RANGE' });
319324
assert.throws(() => ffi.exportBuffer(Buffer.from([1, 2]), ptr, 1), { code: 'ERR_OUT_OF_RANGE' });
320325
assert.throws(() => ffi.exportArrayBuffer('bad', ptr, 4), { code: 'ERR_INVALID_ARG_TYPE' });
326+
assert.throws(() => ffi.exportArrayBuffer({ [Symbol.toStringTag]: 'ArrayBuffer', byteLength: 1 }, ptr, 4), {
327+
code: 'ERR_INVALID_ARG_TYPE',
328+
message: /The "arrayBuffer" argument must be an instance of ArrayBuffer/,
329+
});
321330
assert.throws(() => ffi.exportArrayBuffer(new ArrayBuffer(1), ptr, -1), { code: 'ERR_OUT_OF_RANGE' });
322331
assert.throws(() => ffi.exportArrayBuffer(new ArrayBuffer(2), ptr, 1), { code: 'ERR_OUT_OF_RANGE' });
323332
assert.throws(() => ffi.exportArrayBufferView('bad', ptr, 4), { code: 'ERR_INVALID_ARG_TYPE' });

0 commit comments

Comments
 (0)