diff --git a/src/ffi/types.cc b/src/ffi/types.cc index 7f31845a06736c..cd9fde06dcbfca 100644 --- a/src/ffi/types.cc +++ b/src/ffi/types.cc @@ -164,6 +164,15 @@ Maybe ParseFunctionSignature(Environment* env, if (!ToFFIType(env, arg_str.ToStringView()).To(&arg_type)) { return {}; } + if (arg_type == &ffi_type_void) { + THROW_ERR_INVALID_ARG_VALUE( + env, + "Argument %u of function %s must not be 'void'; " + "use an empty array for no-argument functions", + i, + name); + return {}; + } args.push_back(arg_type); arg_type_names.emplace_back(arg_str.ToString()); diff --git a/test/ffi/test-ffi-void-parameter.js b/test/ffi/test-ffi-void-parameter.js new file mode 100644 index 00000000000000..88bb906bad03e9 --- /dev/null +++ b/test/ffi/test-ffi-void-parameter.js @@ -0,0 +1,29 @@ +// Flags: --experimental-ffi +'use strict'; + +const common = require('../common'); +common.skipIfFFIMissing(); + +const assert = require('node:assert'); +const ffi = require('node:ffi'); +const { libraryPath } = require('./ffi-test-common'); + +// Regression test for https://github.com/nodejs/node/issues/63461 +// 'void' as a parameter type should throw ERR_INVALID_ARG_VALUE +// instead of triggering ERR_INTERNAL_ASSERTION. + +const lib = new ffi.DynamicLibrary(libraryPath); + +try { + assert.throws(() => { + lib.getFunction('add_i32', { return: 'i32', arguments: ['void'] }); + }, { code: 'ERR_INVALID_ARG_VALUE' }); + + assert.throws(() => { + lib.getFunctions({ + add_i32: { return: 'i32', arguments: ['void'] }, + }); + }, { code: 'ERR_INVALID_ARG_VALUE' }); +} finally { + lib.close(); +}