ffi: keep FFI functions non-constructible · nodejs/node@9024ec2 · GitHub
Skip to content

Commit 9024ec2

Browse files
trivikraduh95
authored andcommitted
ffi: keep FFI functions non-constructible
Use concise method functions for Fast API and shared-buffer wrappers, and create native fallback functions with ConstructorBehavior::kThrow, so FFI functions remain non-constructible on all invocation paths. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: codex:gpt-5.6-sol PR-URL: #65184 Fixes: #65183 Reviewed-By: Paolo Insogna <paolo@cowtech.it>
1 parent fdc1e78 commit 9024ec2

4 files changed

Lines changed: 75 additions & 45 deletions

File tree

lib/internal/ffi-shared-buffer.js

Lines changed: 36 additions & 34 deletions

lib/internal/ffi/fast-api.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ function throwIfFastLibraryClosed(state) {
254254
}
255255
}
256256

257+
// Concise methods do not have [[Construct]], unlike function expressions.
258+
// Keep wrappers non-constructible to match the native FFI functions.
257259
function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
258260
if (rawFn === undefined || rawFn === null) {
259261
return rawFn;
@@ -287,7 +289,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
287289
const memory0 = needsRawPointerConversion(t0) || string0;
288290
const fastBufferInvoke = needsPointerLikeConversion(t0) ?
289291
rawFn[kFastBufferInvoke] : undefined;
290-
wrapper = function(a0) {
292+
wrapper = { invoke(a0) {
291293
throwIfFastLibraryClosed(state);
292294
if (arguments.length !== 1) {
293295
throwFFIArgCountError(1, arguments.length);
@@ -312,13 +314,13 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
312314
arg = getRawPointerArg(arg, 0);
313315
}
314316
return rawFn(arg);
315-
};
317+
} }.invoke;
316318
} else if (nargs === 2) {
317319
const c0 = ArrayPrototypeIncludes(indexes, 0);
318320
const c1 = ArrayPrototypeIncludes(indexes, 1);
319321
const t0 = argumentTypes[0];
320322
const t1 = argumentTypes[1];
321-
wrapper = function(a0, a1) {
323+
wrapper = { invoke(a0, a1) {
322324
throwIfFastLibraryClosed(state);
323325
if (arguments.length !== 2) {
324326
throwFFIArgCountError(2, arguments.length);
@@ -332,15 +334,15 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
332334
} finally {
333335
if (stringCall) exitStringConversion(stringState);
334336
}
335-
};
337+
} }.invoke;
336338
} else if (nargs === 3) {
337339
const c0 = ArrayPrototypeIncludes(indexes, 0);
338340
const c1 = ArrayPrototypeIncludes(indexes, 1);
339341
const c2 = ArrayPrototypeIncludes(indexes, 2);
340342
const t0 = argumentTypes[0];
341343
const t1 = argumentTypes[1];
342344
const t2 = argumentTypes[2];
343-
wrapper = function(a0, a1, a2) {
345+
wrapper = { invoke(a0, a1, a2) {
344346
throwIfFastLibraryClosed(state);
345347
if (arguments.length !== 3) {
346348
throwFFIArgCountError(3, arguments.length);
@@ -356,9 +358,9 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
356358
} finally {
357359
if (stringCall) exitStringConversion(stringState);
358360
}
359-
};
361+
} }.invoke;
360362
} else {
361-
wrapper = function(...args) {
363+
wrapper = { invoke(...args) {
362364
throwIfFastLibraryClosed(state);
363365
if (args.length !== nargs) {
364366
throwFFIArgCountError(nargs, args.length);
@@ -382,7 +384,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
382384
} finally {
383385
if (stringCall) exitStringConversion(stringState);
384386
}
385-
};
387+
} }.invoke;
386388
}
387389

388390
return inheritMetadata(wrapper, rawFn, nargs);

src/node_ffi.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,9 @@ MaybeLocal<Function> DynamicLibrary::CreateFunction(
324324
maybe_ret = Function::New(context,
325325
use_sb ? DynamicLibrary::InvokeFunctionSB
326326
: DynamicLibrary::InvokeFunction,
327-
info->object());
327+
info->object(),
328+
0,
329+
v8::ConstructorBehavior::kThrow);
328330
}
329331

330332
Local<Function> ret;
@@ -377,8 +379,11 @@ MaybeLocal<Function> DynamicLibrary::CreateFunction(
377379
// (strings, Buffers, ArrayBuffers, and ArrayBufferViews).
378380
if (has_ptr_args) {
379381
Local<Function> slow_fn;
380-
if (!Function::New(
381-
context, DynamicLibrary::InvokeFunction, info->object())
382+
if (!Function::New(context,
383+
DynamicLibrary::InvokeFunction,
384+
info->object(),
385+
0,
386+
v8::ConstructorBehavior::kThrow)
382387
.ToLocal(&slow_fn)) {
383388
return MaybeLocal<Function>();
384389
}

test/ffi/test-ffi-dynamic-library.js

Lines changed: 21 additions & 0 deletions

0 commit comments

Comments
 (0)