| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent fdc1e78 commit 9024ec2
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -198,6 +198,8 @@ function inheritMetadata(wrapper, rawFn, nargs) { | |||
| 198 | 198 | // arguments out of it into invocation-local storage before `ffi_call` and | |
| 199 | 199 | // reads the return value back only after, so nested/reentrant calls into | |
| 200 | 200 | // the same function are safe. | |
| 201 | + // Concise methods do not have [[Construct]], unlike function expressions, so | ||
| 202 | + // use them below to match the native FFI functions' non-constructible behavior. | ||
| 201 | 203 | function wrapWithSharedBuffer(rawFn, signature) { | |
| 202 | 204 | if (rawFn == null) return rawFn; | |
| 203 | 205 | const buffer = rawFn[kSbSharedBuffer]; | |
@@ -254,7 +256,7 @@ function wrapWithSharedBuffer(rawFn, signature) { | |||
| 254 | 256 | // so arity specialization wouldn't buy much here. | |
| 255 | 257 | assert(slowInvoke !== undefined, | |
| 256 | 258 | 'FFI: shared-buffer raw function with pointer arguments is missing kSbInvokeSlow'); | |
| 257 | - wrapper = function(...args) { | ||
| 259 | + wrapper = { invoke(...args) { | ||
| 258 | 260 | if (args.length !== nargs) { | |
| 259 | 261 | throwFFIArgCountError(nargs, args.length); | |
| 260 | 262 | } | |
@@ -271,7 +273,7 @@ function wrapWithSharedBuffer(rawFn, signature) { | |||
| 271 | 273 | } | |
| 272 | 274 | rawFn(); | |
| 273 | 275 | return retGetter === null ? undefined : retGetter(view, 0, true); | |
| 274 | - }; | ||
| 276 | + } }.invoke; | ||
| 275 | 277 | } else { | |
| 276 | 278 | // Arity specialization avoids the per-call `Array` allocation of | |
| 277 | 279 | // `...args`; the void/non-void split removes a per-call branch on | |
@@ -295,67 +297,67 @@ function buildNumericWrapper( | |||
| 295 | 297 | /* c8 ignore start */ | |
| 296 | 298 | if (nargs === 0) { | |
| 297 | 299 | if (retGetter === null) { | |
| 298 | - return function() { | ||
| 300 | + return { invoke() { | ||
| 299 | 301 | if (arguments.length !== 0) { | |
| 300 | 302 | throwFFIArgCountError(0, arguments.length); | |
| 301 | 303 | } | |
| 302 | 304 | rawFn(); | |
| 303 | - }; | ||
| 305 | + } }.invoke; | ||
| 304 | 306 | } | |
| 305 | - return function() { | ||
| 307 | + return { invoke() { | ||
| 306 | 308 | if (arguments.length !== 0) { | |
| 307 | 309 | throwFFIArgCountError(0, arguments.length); | |
| 308 | 310 | } | |
| 309 | 311 | rawFn(); | |
| 310 | 312 | return retGetter(view, 0, true); | |
| 311 | - }; | ||
| 313 | + } }.invoke; | ||
| 312 | 314 | } | |
| 313 | 315 | /* c8 ignore stop */ | |
| 314 | 316 | if (nargs === 1) { | |
| 315 | 317 | const i0 = argInfos[0]; | |
| 316 | 318 | const o0 = argOffsets[0]; | |
| 317 | 319 | if (retGetter === null) { | |
| 318 | - return function(a0) { | ||
| 320 | + return { invoke(a0) { | ||
| 319 | 321 | if (arguments.length !== 1) { | |
| 320 | 322 | throwFFIArgCountError(1, arguments.length); | |
| 321 | 323 | } | |
| 322 | 324 | writeNumericArg(view, i0, o0, a0, 0); | |
| 323 | 325 | rawFn(); | |
| 324 | - }; | ||
| 326 | + } }.invoke; | ||
| 325 | 327 | } | |
| 326 | - return function(a0) { | ||
| 328 | + return { invoke(a0) { | ||
| 327 | 329 | if (arguments.length !== 1) { | |
| 328 | 330 | throwFFIArgCountError(1, arguments.length); | |
| 329 | 331 | } | |
| 330 | 332 | writeNumericArg(view, i0, o0, a0, 0); | |
| 331 | 333 | rawFn(); | |
| 332 | 334 | return retGetter(view, 0, true); | |
| 333 | - }; | ||
| 335 | + } }.invoke; | ||
| 334 | 336 | } | |
| 335 | 337 | if (nargs === 2) { | |
| 336 | 338 | const i0 = argInfos[0]; | |
| 337 | 339 | const i1 = argInfos[1]; | |
| 338 | 340 | const o0 = argOffsets[0]; | |
| 339 | 341 | const o1 = argOffsets[1]; | |
| 340 | 342 | if (retGetter === null) { | |
| 341 | - return function(a0, a1) { | ||
| 343 | + return { invoke(a0, a1) { | ||
| 342 | 344 | if (arguments.length !== 2) { | |
| 343 | 345 | throwFFIArgCountError(2, arguments.length); | |
| 344 | 346 | } | |
| 345 | 347 | writeNumericArg(view, i0, o0, a0, 0); | |
| 346 | 348 | writeNumericArg(view, i1, o1, a1, 1); | |
| 347 | 349 | rawFn(); | |
| 348 | - }; | ||
| 350 | + } }.invoke; | ||
| 349 | 351 | } | |
| 350 | - return function(a0, a1) { | ||
| 352 | + return { invoke(a0, a1) { | ||
| 351 | 353 | if (arguments.length !== 2) { | |
| 352 | 354 | throwFFIArgCountError(2, arguments.length); | |
| 353 | 355 | } | |
| 354 | 356 | writeNumericArg(view, i0, o0, a0, 0); | |
| 355 | 357 | writeNumericArg(view, i1, o1, a1, 1); | |
| 356 | 358 | rawFn(); | |
| 357 | 359 | return retGetter(view, 0, true); | |
| 358 | - }; | ||
| 360 | + } }.invoke; | ||
| 359 | 361 | } | |
| 360 | 362 | if (nargs === 3) { | |
| 361 | 363 | const i0 = argInfos[0]; | |
@@ -365,17 +367,17 @@ function buildNumericWrapper( | |||
| 365 | 367 | const o1 = argOffsets[1]; | |
| 366 | 368 | const o2 = argOffsets[2]; | |
| 367 | 369 | if (retGetter === null) { | |
| 368 | - return function(a0, a1, a2) { | ||
| 370 | + return { invoke(a0, a1, a2) { | ||
| 369 | 371 | if (arguments.length !== 3) { | |
| 370 | 372 | throwFFIArgCountError(3, arguments.length); | |
| 371 | 373 | } | |
| 372 | 374 | writeNumericArg(view, i0, o0, a0, 0); | |
| 373 | 375 | writeNumericArg(view, i1, o1, a1, 1); | |
| 374 | 376 | writeNumericArg(view, i2, o2, a2, 2); | |
| 375 | 377 | rawFn(); | |
| 376 | - }; | ||
| 378 | + } }.invoke; | ||
| 377 | 379 | } | |
| 378 | - return function(a0, a1, a2) { | ||
| 380 | + return { invoke(a0, a1, a2) { | ||
| 379 | 381 | if (arguments.length !== 3) { | |
| 380 | 382 | throwFFIArgCountError(3, arguments.length); | |
| 381 | 383 | } | |
@@ -384,7 +386,7 @@ function buildNumericWrapper( | |||
| 384 | 386 | writeNumericArg(view, i2, o2, a2, 2); | |
| 385 | 387 | rawFn(); | |
| 386 | 388 | return retGetter(view, 0, true); | |
| 387 | - }; | ||
| 389 | + } }.invoke; | ||
| 388 | 390 | } | |
| 389 | 391 | if (nargs === 4) { | |
| 390 | 392 | const i0 = argInfos[0]; | |
@@ -396,7 +398,7 @@ function buildNumericWrapper( | |||
| 396 | 398 | const o2 = argOffsets[2]; | |
| 397 | 399 | const o3 = argOffsets[3]; | |
| 398 | 400 | if (retGetter === null) { | |
| 399 | - return function(a0, a1, a2, a3) { | ||
| 401 | + return { invoke(a0, a1, a2, a3) { | ||
| 400 | 402 | if (arguments.length !== 4) { | |
| 401 | 403 | throwFFIArgCountError(4, arguments.length); | |
| 402 | 404 | } | |
@@ -405,9 +407,9 @@ function buildNumericWrapper( | |||
| 405 | 407 | writeNumericArg(view, i2, o2, a2, 2); | |
| 406 | 408 | writeNumericArg(view, i3, o3, a3, 3); | |
| 407 | 409 | rawFn(); | |
| 408 | - }; | ||
| 410 | + } }.invoke; | ||
| 409 | 411 | } | |
| 410 | - return function(a0, a1, a2, a3) { | ||
| 412 | + return { invoke(a0, a1, a2, a3) { | ||
| 411 | 413 | if (arguments.length !== 4) { | |
| 412 | 414 | throwFFIArgCountError(4, arguments.length); | |
| 413 | 415 | } | |
@@ -417,7 +419,7 @@ function buildNumericWrapper( | |||
| 417 | 419 | writeNumericArg(view, i3, o3, a3, 3); | |
| 418 | 420 | rawFn(); | |
| 419 | 421 | return retGetter(view, 0, true); | |
| 420 | - }; | ||
| 422 | + } }.invoke; | ||
| 421 | 423 | } | |
| 422 | 424 | if (nargs === 5) { | |
| 423 | 425 | const i0 = argInfos[0]; | |
@@ -431,7 +433,7 @@ function buildNumericWrapper( | |||
| 431 | 433 | const o3 = argOffsets[3]; | |
| 432 | 434 | const o4 = argOffsets[4]; | |
| 433 | 435 | if (retGetter === null) { | |
| 434 | - return function(a0, a1, a2, a3, a4) { | ||
| 436 | + return { invoke(a0, a1, a2, a3, a4) { | ||
| 435 | 437 | if (arguments.length !== 5) { | |
| 436 | 438 | throwFFIArgCountError(5, arguments.length); | |
| 437 | 439 | } | |
@@ -441,9 +443,9 @@ function buildNumericWrapper( | |||
| 441 | 443 | writeNumericArg(view, i3, o3, a3, 3); | |
| 442 | 444 | writeNumericArg(view, i4, o4, a4, 4); | |
| 443 | 445 | rawFn(); | |
| 444 | - }; | ||
| 446 | + } }.invoke; | ||
| 445 | 447 | } | |
| 446 | - return function(a0, a1, a2, a3, a4) { | ||
| 448 | + return { invoke(a0, a1, a2, a3, a4) { | ||
| 447 | 449 | if (arguments.length !== 5) { | |
| 448 | 450 | throwFFIArgCountError(5, arguments.length); | |
| 449 | 451 | } | |
@@ -454,7 +456,7 @@ function buildNumericWrapper( | |||
| 454 | 456 | writeNumericArg(view, i4, o4, a4, 4); | |
| 455 | 457 | rawFn(); | |
| 456 | 458 | return retGetter(view, 0, true); | |
| 457 | - }; | ||
| 459 | + } }.invoke; | ||
| 458 | 460 | } | |
| 459 | 461 | if (nargs === 6) { | |
| 460 | 462 | const i0 = argInfos[0]; | |
@@ -470,7 +472,7 @@ function buildNumericWrapper( | |||
| 470 | 472 | const o4 = argOffsets[4]; | |
| 471 | 473 | const o5 = argOffsets[5]; | |
| 472 | 474 | if (retGetter === null) { | |
| 473 | - return function(a0, a1, a2, a3, a4, a5) { | ||
| 475 | + return { invoke(a0, a1, a2, a3, a4, a5) { | ||
| 474 | 476 | if (arguments.length !== 6) { | |
| 475 | 477 | throwFFIArgCountError(6, arguments.length); | |
| 476 | 478 | } | |
@@ -481,9 +483,9 @@ function buildNumericWrapper( | |||
| 481 | 483 | writeNumericArg(view, i4, o4, a4, 4); | |
| 482 | 484 | writeNumericArg(view, i5, o5, a5, 5); | |
| 483 | 485 | rawFn(); | |
| 484 | - }; | ||
| 486 | + } }.invoke; | ||
| 485 | 487 | } | |
| 486 | - return function(a0, a1, a2, a3, a4, a5) { | ||
| 488 | + return { invoke(a0, a1, a2, a3, a4, a5) { | ||
| 487 | 489 | if (arguments.length !== 6) { | |
| 488 | 490 | throwFFIArgCountError(6, arguments.length); | |
| 489 | 491 | } | |
@@ -495,22 +497,22 @@ function buildNumericWrapper( | |||
| 495 | 497 | writeNumericArg(view, i5, o5, a5, 5); | |
| 496 | 498 | rawFn(); | |
| 497 | 499 | return retGetter(view, 0, true); | |
| 498 | - }; | ||
| 500 | + } }.invoke; | ||
| 499 | 501 | } | |
| 500 | 502 | // 7+ args: further specialization is diminishing returns and bloats | |
| 501 | 503 | // this builder. | |
| 502 | 504 | if (retGetter === null) { | |
| 503 | - return function(...args) { | ||
| 505 | + return { invoke(...args) { | ||
| 504 | 506 | if (args.length !== nargs) { | |
| 505 | 507 | throwFFIArgCountError(nargs, args.length); | |
| 506 | 508 | } | |
| 507 | 509 | for (let i = 0; i < nargs; i++) { | |
| 508 | 510 | writeNumericArg(view, argInfos[i], argOffsets[i], args[i], i); | |
| 509 | 511 | } | |
| 510 | 512 | rawFn(); | |
| 511 | - }; | ||
| 513 | + } }.invoke; | ||
| 512 | 514 | } | |
| 513 | - return function(...args) { | ||
| 515 | + return { invoke(...args) { | ||
| 514 | 516 | if (args.length !== nargs) { | |
| 515 | 517 | throwFFIArgCountError(nargs, args.length); | |
| 516 | 518 | } | |
@@ -519,7 +521,7 @@ function buildNumericWrapper( | |||
| 519 | 521 | } | |
| 520 | 522 | rawFn(); | |
| 521 | 523 | return retGetter(view, 0, true); | |
| 522 | - }; | ||
| 524 | + } }.invoke; | ||
| 523 | 525 | } | |
| 524 | 526 | ||
| 525 | 527 | module.exports = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -254,6 +254,8 @@ function throwIfFastLibraryClosed(state) { | |||
| 254 | 254 | } | |
| 255 | 255 | } | |
| 256 | 256 | ||
| 257 | + // Concise methods do not have [[Construct]], unlike function expressions. | ||
| 258 | + // Keep wrappers non-constructible to match the native FFI functions. | ||
| 257 | 259 | function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) { | |
| 258 | 260 | if (rawFn === undefined || rawFn === null) { | |
| 259 | 261 | return rawFn; | |
@@ -287,7 +289,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) { | |||
| 287 | 289 | const memory0 = needsRawPointerConversion(t0) || string0; | |
| 288 | 290 | const fastBufferInvoke = needsPointerLikeConversion(t0) ? | |
| 289 | 291 | rawFn[kFastBufferInvoke] : undefined; | |
| 290 | - wrapper = function(a0) { | ||
| 292 | + wrapper = { invoke(a0) { | ||
| 291 | 293 | throwIfFastLibraryClosed(state); | |
| 292 | 294 | if (arguments.length !== 1) { | |
| 293 | 295 | throwFFIArgCountError(1, arguments.length); | |
@@ -312,13 +314,13 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) { | |||
| 312 | 314 | arg = getRawPointerArg(arg, 0); | |
| 313 | 315 | } | |
| 314 | 316 | return rawFn(arg); | |
| 315 | - }; | ||
| 317 | + } }.invoke; | ||
| 316 | 318 | } else if (nargs === 2) { | |
| 317 | 319 | const c0 = ArrayPrototypeIncludes(indexes, 0); | |
| 318 | 320 | const c1 = ArrayPrototypeIncludes(indexes, 1); | |
| 319 | 321 | const t0 = argumentTypes[0]; | |
| 320 | 322 | const t1 = argumentTypes[1]; | |
| 321 | - wrapper = function(a0, a1) { | ||
| 323 | + wrapper = { invoke(a0, a1) { | ||
| 322 | 324 | throwIfFastLibraryClosed(state); | |
| 323 | 325 | if (arguments.length !== 2) { | |
| 324 | 326 | throwFFIArgCountError(2, arguments.length); | |
@@ -332,15 +334,15 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) { | |||
| 332 | 334 | } finally { | |
| 333 | 335 | if (stringCall) exitStringConversion(stringState); | |
| 334 | 336 | } | |
| 335 | - }; | ||
| 337 | + } }.invoke; | ||
| 336 | 338 | } else if (nargs === 3) { | |
| 337 | 339 | const c0 = ArrayPrototypeIncludes(indexes, 0); | |
| 338 | 340 | const c1 = ArrayPrototypeIncludes(indexes, 1); | |
| 339 | 341 | const c2 = ArrayPrototypeIncludes(indexes, 2); | |
| 340 | 342 | const t0 = argumentTypes[0]; | |
| 341 | 343 | const t1 = argumentTypes[1]; | |
| 342 | 344 | const t2 = argumentTypes[2]; | |
| 343 | - wrapper = function(a0, a1, a2) { | ||
| 345 | + wrapper = { invoke(a0, a1, a2) { | ||
| 344 | 346 | throwIfFastLibraryClosed(state); | |
| 345 | 347 | if (arguments.length !== 3) { | |
| 346 | 348 | throwFFIArgCountError(3, arguments.length); | |
@@ -356,9 +358,9 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) { | |||
| 356 | 358 | } finally { | |
| 357 | 359 | if (stringCall) exitStringConversion(stringState); | |
| 358 | 360 | } | |
| 359 | - }; | ||
| 361 | + } }.invoke; | ||
| 360 | 362 | } else { | |
| 361 | - wrapper = function(...args) { | ||
| 363 | + wrapper = { invoke(...args) { | ||
| 362 | 364 | throwIfFastLibraryClosed(state); | |
| 363 | 365 | if (args.length !== nargs) { | |
| 364 | 366 | throwFFIArgCountError(nargs, args.length); | |
@@ -382,7 +384,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) { | |||
| 382 | 384 | } finally { | |
| 383 | 385 | if (stringCall) exitStringConversion(stringState); | |
| 384 | 386 | } | |
| 385 | - }; | ||
| 387 | + } }.invoke; | ||
| 386 | 388 | } | |
| 387 | 389 | ||
| 388 | 390 | return inheritMetadata(wrapper, rawFn, nargs); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -324,7 +324,9 @@ MaybeLocal<Function> DynamicLibrary::CreateFunction( | |||
| 324 | 324 | maybe_ret = Function::New(context, | |
| 325 | 325 | use_sb ? DynamicLibrary::InvokeFunctionSB | |
| 326 | 326 | : DynamicLibrary::InvokeFunction, | |
| 327 | - info->object()); | ||
| 327 | + info->object(), | ||
| 328 | + 0, | ||
| 329 | + v8::ConstructorBehavior::kThrow); | ||
| 328 | 330 | } | |
| 329 | 331 | ||
| 330 | 332 | Local<Function> ret; | |
@@ -377,8 +379,11 @@ MaybeLocal<Function> DynamicLibrary::CreateFunction( | |||
| 377 | 379 | // (strings, Buffers, ArrayBuffers, and ArrayBufferViews). | |
| 378 | 380 | if (has_ptr_args) { | |
| 379 | 381 | 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) | ||
| 382 | 387 | .ToLocal(&slow_fn)) { | |
| 383 | 388 | return MaybeLocal<Function>(); | |
| 384 | 389 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -67,6 +67,27 @@ test('dlopen resolves functions from definitions', () => { | |||
| 67 | 67 | } | |
| 68 | 68 | }); | |
| 69 | 69 | ||
| 70 | + test('FFI functions are not constructible', () => { | ||
| 71 | + const { lib, functions } = ffi.dlopen(libraryPath, { | ||
| 72 | + add_i32: fixtureSymbols.add_i32, | ||
| 73 | + multiply_f64: fixtureSymbols.multiply_f64, | ||
| 74 | + }); | ||
| 75 | + | ||
| 76 | + try { | ||
| 77 | + assert.strictEqual(Object.hasOwn(functions.add_i32, 'prototype'), false); | ||
| 78 | + assert.strictEqual( | ||
| 79 | + Object.hasOwn(functions.multiply_f64, 'prototype'), false); | ||
| 80 | + assert.throws( | ||
| 81 | + () => Reflect.construct(functions.add_i32, [20, 22]), | ||
| 82 | + TypeError); | ||
| 83 | + assert.throws( | ||
| 84 | + () => Reflect.construct(functions.multiply_f64, [6, 7]), | ||
| 85 | + TypeError); | ||
| 86 | + } finally { | ||
| 87 | + lib.close(); | ||
| 88 | + } | ||
| 89 | + }); | ||
| 90 | + | ||
| 70 | 91 | test('DynamicLibrary exposes functions and symbols', () => { | |
| 71 | 92 | const lib = new ffi.DynamicLibrary(libraryPath); | |
| 72 | 93 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments