Version
main (a48e33f)
Platform
Darwin 25.5.0 Darwin Kernel Version 25.5.0: Tue Jun 9 22:28:34 PDT 2026; root:xnu-12377.121.10~1/RELEASE_ARM64_T6041 arm64
Subsystem
ffi
What steps will reproduce the bug?
// node --experimental-ffi repro.js
const ffi = require('node:ffi');
console.log(ffi.getUint8()); // pointer omitted
console.log(ffi.setUint8()); // pointer omitted
console.log(ffi.toBuffer(1n)); // length omitted
// The same arguments, passed explicitly.
try { ffi.getUint8(undefined); } catch (err) { console.log(err.message); }
try { ffi.toBuffer(1n, undefined); } catch (err) { console.log(err.message); }
How often does it reproduce? Is there a required condition?
Always. All 22 helpers behave the same way: the ten getters, the ten setters, toBuffer() and toArrayBuffer().
What is the expected behavior? Why is that the expected behavior?
Omitting a required argument should throw, like passing it explicitly as undefined already does.
The documented signatures are ffi.getInt8(pointer[, offset]), ffi.setInt8(pointer, offset, value) and ffi.toBuffer(pointer, length[, copy]), and the getters are documented to return a number or a bigint. The helpers are inconsistent among themselves too: setUint8(ptr) throws Expected an offset argument, so only a missing first argument goes unreported.
What do you see instead?
undefined
undefined
undefined
The pointer must be a bigint
The length must be a number
GetValidatedPointerAddress() and GetValidatedSize() already reject undefined. The args.Length() test in front of them short-circuits the call and returns Nothing without scheduling an exception:
|
Maybe<std::pair<uint8_t*, size_t>> GetValidatedPointerAndOffset( |
|
Environment* env, const FunctionCallbackInfo<Value>& args) { |
|
uintptr_t raw_ptr; |
|
if (args.Length() < 1 || |
|
!GetValidatedPointerAddress(env, args[0], "pointer").To(&raw_ptr)) { |
|
return {}; |
|
} |
The same shape guards the setters (L207), the length of ToBuffer() (L559) and of ToArrayBuffer() (L621), and both arguments of ExportBytes() (L697, L703).
Additional information
These are raw memory helpers, so the silent undefined is easy to miss: if (ffi.getUint8(ptr)) written with the pointer left out is falsy exactly like a zero byte, and ffi.setUint8() reports success for a write that never happened.
The tests do not look deliberate. FunctionCallbackInfo::operator[] returns Undefined for an out-of-range index, which is exactly the value these validators reject, and these six are the only tests in src/ where args.Length() can skip a call that throws (the only other Length() tests that guard a call at all guard Buffer::HasInstance(), which cannot throw). They arrived with the module in d0fa608 and survived fe41105 (#62858), which reworked the surrounding error handling; I found no mention of argument count in the reviews of #62072, #62762 or #62858.
Refs: #62072
Refs: #62858
Refs: #65342
Version
main (a48e33f)
Platform
Subsystem
ffi
What steps will reproduce the bug?
How often does it reproduce? Is there a required condition?
Always. All 22 helpers behave the same way: the ten getters, the ten setters,
toBuffer()andtoArrayBuffer().What is the expected behavior? Why is that the expected behavior?
Omitting a required argument should throw, like passing it explicitly as
undefinedalready does.The documented signatures are
ffi.getInt8(pointer[, offset]),ffi.setInt8(pointer, offset, value)andffi.toBuffer(pointer, length[, copy]), and the getters are documented to return anumberor abigint. The helpers are inconsistent among themselves too:setUint8(ptr)throwsExpected an offset argument, so only a missing first argument goes unreported.What do you see instead?
GetValidatedPointerAddress()andGetValidatedSize()already rejectundefined. Theargs.Length()test in front of them short-circuits the call and returnsNothingwithout scheduling an exception:node/src/ffi/data.cc
Lines 163 to 169 in a48e33f
The same shape guards the setters (
L207), the length ofToBuffer()(L559) and ofToArrayBuffer()(L621), and both arguments ofExportBytes()(L697,L703).Additional information
These are raw memory helpers, so the silent
undefinedis easy to miss:if (ffi.getUint8(ptr))written with the pointer left out is falsy exactly like a zero byte, andffi.setUint8()reports success for a write that never happened.The tests do not look deliberate.
FunctionCallbackInfo::operator[]returnsUndefinedfor an out-of-range index, which is exactly the value these validators reject, and these six are the only tests insrc/whereargs.Length()can skip a call that throws (the only otherLength()tests that guard a call at all guardBuffer::HasInstance(), which cannot throw). They arrived with the module in d0fa608 and survived fe41105 (#62858), which reworked the surrounding error handling; I found no mention of argument count in the reviews of #62072, #62762 or #62858.Refs: #62072
Refs: #62858
Refs: #65342