@@ -31,18 +31,14 @@ const {
3131 TypeError,
3232} = primordials ;
3333
34- const {
35- codes : {
36- ERR_INTERNAL_ASSERTION ,
37- } ,
38- } = require ( 'internal/errors' ) ;
34+ const assert = require ( 'internal/assert' ) ;
3935
4036const {
4137 DynamicLibrary,
4238 charIsSigned,
39+ kSbArguments,
4340 kSbInvokeSlow,
44- kSbParams,
45- kSbResult,
41+ kSbReturn,
4642 kSbSharedBuffer,
4743 uintptrMax,
4844} = internalBinding ( 'ffi' ) ;
@@ -159,11 +155,9 @@ function writeNumericArg(view, info, offset, arg, index) {
159155 return ;
160156 }
161157
162- /* c8 ignore start */
163158 // Unreachable: caller filters out non-numeric kinds.
164- throw new ERR_INTERNAL_ASSERTION (
165- `FFI: writeNumericArg reached with unexpected kind="${ kind } "` ) ;
166- /* c8 ignore stop */
159+ /* c8 ignore next */
160+ assert . fail ( `FFI: writeNumericArg reached with unexpected kind="${ kind } "` ) ;
167161}
168162
169163// Returns true on fast-path success, false when the caller must fall back
@@ -208,51 +202,46 @@ function inheritMetadata(wrapper, rawFn, nargs) {
208202// arguments out of it into invocation-local storage before `ffi_call` and
209203// reads the return value back only after, so nested/reentrant calls into
210204// the same function are safe.
211- function wrapWithSharedBuffer ( rawFn , parameters , resultType ) {
212- if ( rawFn === undefined || rawFn === null ) return rawFn ;
205+ function wrapWithSharedBuffer ( rawFn , signature ) {
206+ if ( rawFn == null ) return rawFn ;
213207 const buffer = rawFn [ kSbSharedBuffer ] ;
214208 if ( buffer === undefined ) return rawFn ;
215209
216210 // Callers without explicit signature info (the `functions` accessor
217- // patch below) rely on the `kSbParams ` / `kSbResult ` metadata attached
211+ // patch below) rely on the `kSbArguments ` / `kSbReturn ` metadata attached
218212 // by the native `CreateFunction`.
219- if ( parameters === undefined ) parameters = rawFn [ kSbParams ] ;
220- if ( resultType === undefined ) resultType = rawFn [ kSbResult ] ;
221- // `CreateFunction` always attaches these for SB-eligible functions.
222- // Missing here means the native side and this wrapper are out of sync.
223- /* c8 ignore start */
224- if ( parameters === undefined || resultType === undefined ) {
225- throw new ERR_INTERNAL_ASSERTION (
226- 'FFI: shared-buffer raw function is missing kSbParams or kSbResult' ) ;
213+ let argumentTypes , returnType ;
214+ if ( signature === undefined ) {
215+ argumentTypes = rawFn [ kSbArguments ] ;
216+ returnType = rawFn [ kSbReturn ] ;
217+
218+ // `CreateFunction` always attaches these for SB-eligible functions.
219+ // Missing here means the native side and this wrapper are out of sync.
220+ assert ( argumentTypes !== undefined && returnType !== undefined ,
221+ 'FFI: shared-buffer raw function is missing kSbArguments or kSbReturn' ) ;
222+ } else {
223+ argumentTypes = signature . arguments ?? [ ] ;
224+ returnType = signature . return ?? 'void' ;
227225 }
228- /* c8 ignore stop */
229226
230227 const slowInvoke = rawFn [ kSbInvokeSlow ] ;
231228 const view = new DataView ( buffer ) ;
232229 let retGetter = null ;
233- if ( resultType !== 'void' ) {
234- const retInfo = sbTypeInfo [ resultType ] ;
235- /* c8 ignore start */
236- if ( retInfo === undefined ) {
237- throw new ERR_INTERNAL_ASSERTION (
238- `FFI: shared-buffer type table missing entry for result type "${ resultType } "` ) ;
239- }
240- /* c8 ignore stop */
230+ if ( returnType !== 'void' ) {
231+ const retInfo = sbTypeInfo [ returnType ] ;
232+ assert ( retInfo !== undefined ,
233+ `FFI: shared-buffer type table missing entry for return type "${ returnType } "` ) ;
241234 retGetter = retInfo . get ;
242235 }
243236
244- const nargs = parameters . length ;
237+ const nargs = argumentTypes . length ;
245238 const argInfos = [ ] ;
246239 const argOffsets = [ ] ;
247240 let anyPointer = false ;
248241 for ( let i = 0 ; i < nargs ; i ++ ) {
249- const info = sbTypeInfo [ parameters [ i ] ] ;
250- /* c8 ignore start */
251- if ( info === undefined ) {
252- throw new ERR_INTERNAL_ASSERTION (
253- `FFI: shared-buffer type table missing entry for parameter type "${ parameters [ i ] } "` ) ;
254- }
255- /* c8 ignore stop */
242+ const info = sbTypeInfo [ argumentTypes [ i ] ] ;
243+ assert ( info !== undefined ,
244+ `FFI: shared-buffer type table missing entry for argument type "${ argumentTypes [ i ] } "` ) ;
256245 // Push the `sbTypeInfo` entry directly (entries with the same `kind`
257246 // share a shape, keeping `writeNumericArg`'s call sites
258247 // low-polymorphism) and store offsets in a parallel array to avoid
@@ -267,13 +256,8 @@ function wrapWithSharedBuffer(rawFn, parameters, resultType) {
267256 // Pointer signatures need a per-arg runtime type check and fall back
268257 // to the native slow-path invoker for non-BigInt pointer arguments,
269258 // so arity specialization wouldn't buy much here.
270- /* c8 ignore start */
271- if ( slowInvoke === undefined ) {
272- throw new ERR_INTERNAL_ASSERTION (
273- 'FFI: shared-buffer raw function with pointer arguments is ' +
274- 'missing kSbInvokeSlow' ) ;
275- }
276- /* c8 ignore stop */
259+ assert ( slowInvoke !== undefined ,
260+ 'FFI: shared-buffer raw function with pointer arguments is missing kSbInvokeSlow' ) ;
277261 wrapper = function ( ...args ) {
278262 if ( args . length !== nargs ) {
279263 throwFFIArgCountError ( nargs , args . length ) ;
@@ -542,19 +526,6 @@ function buildNumericWrapper(
542526 } ;
543527}
544528
545- // Accept-set mirrors the native `ParseFunctionSignature` in
546- // `src/ffi/types.cc`. `ParseFunctionSignature` additionally throws when
547- // multiple aliases are set at once. The wrapper runs before the native
548- // call, so those conflicts still surface from the native side regardless
549- // of which alias we happen to read here.
550- function sigParams ( sig ) {
551- return sig . parameters ?? sig . arguments ?? [ ] ;
552- }
553-
554- function sigResult ( sig ) {
555- return sig . result ?? sig . return ?? sig . returns ?? 'void' ;
556- }
557-
558529// The native invoker for SB-eligible symbols is `InvokeFunctionSB`, which
559530// reads arguments from the shared buffer populated by
560531// `wrapWithSharedBuffer`. These patches make sure every path that surfaces
@@ -563,11 +534,11 @@ function sigResult(sig) {
563534const rawGetFunction = DynamicLibrary . prototype . getFunction ;
564535const rawGetFunctions = DynamicLibrary . prototype . getFunctions ;
565536
566- DynamicLibrary . prototype . getFunction = function getFunction ( name , sig ) {
567- // Native `DynamicLibrary::GetFunction` validates `sig `, so by the time
568- // we have `raw` we know `sig ` is a valid object.
569- const raw = FunctionPrototypeCall ( rawGetFunction , this , name , sig ) ;
570- return wrapWithSharedBuffer ( raw , sigParams ( sig ) , sigResult ( sig ) ) ;
537+ DynamicLibrary . prototype . getFunction = function getFunction ( name , signature ) {
538+ // Native `DynamicLibrary::GetFunction` validates `signature `, so by the time
539+ // we have `raw` we know `signature ` is a valid object.
540+ const raw = FunctionPrototypeCall ( rawGetFunction , this , name , signature ) ;
541+ return wrapWithSharedBuffer ( raw , signature ) ;
571542} ;
572543
573544DynamicLibrary . prototype . getFunctions = function getFunctions ( definitions ) {
@@ -583,13 +554,12 @@ DynamicLibrary.prototype.getFunctions = function getFunctions(definitions) {
583554 for ( let i = 0 ; i < keys . length ; i ++ ) {
584555 const name = keys [ i ] ;
585556 // No `definitions`: native side returned every cached function, so we
586- // wrap using each function's own `kSbParams ` / `kSbResult ` metadata
557+ // wrap using each function's own `kSbArguments ` / `kSbReturn ` metadata
587558 // (same fallback as the `functions` accessor).
588559 if ( definitions === undefined ) {
589560 out [ name ] = wrapWithSharedBuffer ( raw [ name ] ) ;
590561 } else {
591- const sig = definitions [ name ] ;
592- out [ name ] = wrapWithSharedBuffer ( raw [ name ] , sigParams ( sig ) , sigResult ( sig ) ) ;
562+ out [ name ] = wrapWithSharedBuffer ( raw [ name ] , definitions [ name ] ) ;
593563 }
594564 }
595565 return out ;
@@ -602,16 +572,12 @@ DynamicLibrary.prototype.getFunctions = function getFunctions(definitions) {
602572 // uninitialized buffer.
603573 const functionsDescriptor =
604574 ObjectGetOwnPropertyDescriptor ( DynamicLibrary . prototype , 'functions' ) ;
605- /* c8 ignore start */
606- if ( functionsDescriptor === undefined || ! functionsDescriptor . get ) {
607- // Missing getter means the native and JS sides are out of sync; silently
608- // skipping the patch would expose the fast-path-against-uninitialized-buffer
609- // footgun this whole block exists to prevent.
610- throw new ERR_INTERNAL_ASSERTION (
611- 'FFI: DynamicLibrary.prototype.functions accessor not found or has no getter' ) ;
612- }
613- /* c8 ignore stop */
614- const origGetter = functionsDescriptor . get ;
575+ const origGetter = functionsDescriptor ?. get ;
576+ // Missing getter means the native and JS sides are out of sync; silently
577+ // skipping the patch would expose the fast-path-against-uninitialized-buffer
578+ // footgun this whole block exists to prevent.
579+ assert ( origGetter !== undefined ,
580+ 'FFI: DynamicLibrary.prototype.functions accessor not found or has no getter' ) ;
615581 ObjectDefineProperty ( DynamicLibrary . prototype , 'functions' , {
616582 __proto__ : null ,
617583 configurable : true ,
0 commit comments