Commit 463711aa555 for nodejs

commit 463711aa555f8bdaf72547721a4f4bc27190b67b
Author: Trivikram Kamat <trivikr.dev@gmail.com>
Date:   Fri Oct 2 00:35:11 2026 -0700

    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
    PR-URL: https://github.com/nodejs/node/pull/66371
    Fixes: https://github.com/nodejs/node/issues/66370
    Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
    Reviewed-By: Paolo Insogna <paolo@cowtech.it>

diff --git a/src/node_ffi.cc b/src/node_ffi.cc
index 7cd865484fc..4ef22a80a42 100644
--- a/src/node_ffi.cc
+++ b/src/node_ffi.cc
@@ -296,10 +296,13 @@ MaybeLocal<Function> 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 e6bedfab967..e2994c89523 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);
       }