Skip to content

Commit 669fac1

Browse files
committed
ffi: reject direct SharedArrayBuffer pointers
Reject direct SharedArrayBuffer pointer arguments in the JavaScript wrapper and native fast-buffer helper. This keeps validation behavior consistent before and after optimization. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: codex:gpt-5.6-sol
1 parent d14729d commit 669fac1

3 files changed

Lines changed: 32 additions & 10 deletions

File tree

lib/internal/ffi/fast-api.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const {
1818
} = require('buffer');
1919

2020
const {
21-
isAnyArrayBuffer,
2221
isArrayBuffer,
2322
isArrayBufferView,
2423
isDataView,
@@ -130,7 +129,7 @@ function hasStringPointerArg(type, value) {
130129

131130
function hasPointerMemoryArg(type, value) {
132131
return (needsRawPointerConversion(type) || needsStringPointerConversion(type)) &&
133-
(isArrayBufferView(value) || isAnyArrayBuffer(value));
132+
(isArrayBufferView(value) || isArrayBuffer(value));
134133
}
135134

136135
function enterStringConversion(state) {
@@ -310,7 +309,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
310309
} finally {
311310
exitStringConversion(stringState);
312311
}
313-
} else if (memory0 && (isArrayBufferView(arg) || isAnyArrayBuffer(arg))) {
312+
} else if (memory0 && (isArrayBufferView(arg) || isArrayBuffer(arg))) {
314313
if (fastBufferInvoke !== undefined) {
315314
return fastBufferInvoke(arg);
316315
}

src/ffi/fast.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,10 @@ extern "C" uintptr_t node_ffi_fast_buffer_data(v8::Local<v8::Value> value,
248248
constexpr uintptr_t kInvalidBuffer = std::numeric_limits<uintptr_t>::max();
249249
v8::Isolate* isolate = options != nullptr ? options->isolate : nullptr;
250250

251-
// Accept only memory-backed JS values in the native helper. Other pointer
252-
// conversions, including strings, stay in the JS wrapper so their temporary
253-
// lifetime is explicit.
251+
// Accept only the memory-backed JS values supported by ToFFIArgument in the
252+
// native helper. Other pointer conversions, including strings and direct
253+
// SharedArrayBuffers, stay in the JS wrapper so validation and temporary
254+
// lifetimes match the generic path.
254255
if (value->IsArrayBufferView()) {
255256
v8::Local<v8::ArrayBufferView> view = value.As<v8::ArrayBufferView>();
256257
if (view->Buffer()->WasDetached()) {
@@ -281,9 +282,6 @@ extern "C" uintptr_t node_ffi_fast_buffer_data(v8::Local<v8::Value> value,
281282
}
282283
return PointerFromValue(value);
283284
}
284-
if (value->IsSharedArrayBuffer()) {
285-
return PointerFromValue(value);
286-
}
287285

288286
if (isolate != nullptr) {
289287
// No HandleScope is active during a Fast API call, so open one before

test/ffi/test-ffi-fast-buffer.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Flags: --experimental-ffi --expose-internals
1+
// Flags: --experimental-ffi --expose-internals --allow-natives-syntax
22
'use strict';
33

44
const common = require('../common');
@@ -70,6 +70,31 @@ test('fast FFI buffer arguments reject invalid values', () => {
7070
}
7171
});
7272

73+
test('optimized pointer arguments reject direct SharedArrayBuffers', () => {
74+
const lib = new ffi.DynamicLibrary(libraryPath);
75+
const firstByte = lib.getFunction('first_byte', {
76+
arguments: ['pointer'],
77+
return: 'u8',
78+
});
79+
const regular = new ArrayBuffer(1);
80+
const shared = new SharedArrayBuffer(1);
81+
const expected = { code: 'ERR_INVALID_ARG_VALUE' };
82+
83+
try {
84+
assert.throws(() => firstByte(shared), expected);
85+
86+
eval('%PrepareFunctionForOptimization(firstByte)');
87+
firstByte(regular);
88+
firstByte(regular);
89+
eval('%OptimizeFunctionOnNextCall(firstByte)');
90+
firstByte(regular);
91+
92+
assert.throws(() => firstByte(shared), expected);
93+
} finally {
94+
lib.close();
95+
}
96+
});
97+
7398
test('fast FFI string buffers survive reentrant callbacks', {
7499
// Bundled libffi callbacks crash on SmartOS.
75100
skip: common.isSunOS,

0 commit comments

Comments
 (0)