From f4488087cecc2a686a9f942f8bc3cb1ca3e57ffc Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:53:19 -0700 Subject: [PATCH] ffi: validate pointer ranges in optimized calls On x64 SysV and arm64, a Fast API signature with two or more arguments that uses only pointer and float types got no JS wrapper. V8 then truncated pointer BigInts silently. With `-1n` or `2n ** 64n + 5n`, cold calls threw ERR_INVALID_ARG_VALUE, while optimized calls passed 0xffffffffffffffff or 5 to native code. Use the argument wrapper for any signature with a pointer argument. Signed-off-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Assisted-by: claude:opus-5.5 --- src/node_ffi.cc | 9 ++++++--- test/ffi/test-ffi-fast-integer-validation.js | 10 +++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/node_ffi.cc b/src/node_ffi.cc index 732657a368ef..43bd090de7fe 100644 --- a/src/node_ffi.cc +++ b/src/node_ffi.cc @@ -294,10 +294,13 @@ MaybeLocal DynamicLibrary::CreateFunction( bool has_ptr_args = use_sb && SignatureHasPointerArgs(*fn); // Signatures that need JS-side conversion or validation use a wrapper, as // do all fast signatures on platforms without a native library guard. + // Pointer arguments need the wrapper's range check because V8 truncates + // BigInts passed to Fast API uint64 parameters. bool needs_fast_argument_wrapper = - use_fast_api && (SignatureNeedsRawPointerConversions(*fn) || - SignatureNeedsFastIntegerValidation(*fn) || - !info->fast_metadata->guards_library); + use_fast_api && + (SignatureNeedsRawPointerConversions(*fn) || + SignatureNeedsFastIntegerValidation(*fn) || + SignatureHasPointerArgs(*fn) || !info->fast_metadata->guards_library); // A single pointer-like parameter can get a separate Buffer-aware Fast API // entrypoint so Buffer calls avoid JS pointer extraction. bool needs_fast_buffer_invoke = diff --git a/test/ffi/test-ffi-fast-integer-validation.js b/test/ffi/test-ffi-fast-integer-validation.js index e6bedfab967c..e2994c895233 100644 --- a/test/ffi/test-ffi-fast-integer-validation.js +++ b/test/ffi/test-ffi-fast-integer-validation.js @@ -83,15 +83,23 @@ test('fast FFI validates pointer BigInt ranges', () => { arguments: [type, 'u64'], return: 'u64', }); + // Only pointer-like arguments, so no integer type forces the wrapper. + const stringConcat = lib.getFunction('string_concat', { + arguments: [type, type], + return: 'pointer', + }); function callSingle(value) { return identityPointer(value); } function callMultiple(value) { return sumBuffer(value, 0n); } + function callPointers(value) { return stringConcat(value, 0n); } + optimize(callSingle, 0n); optimize(callMultiple, 0n); + optimize(callPointers, 0n); const expect = { code: 'ERR_INVALID_ARG_VALUE' }; - for (const call of [callSingle, callMultiple]) { + for (const call of [callSingle, callMultiple, callPointers]) { assert.throws(() => call(-1n), expect); assert.throws(() => call((2n ** 64n) + 5n), expect); }