22
33const {
44 ArrayPrototypeIncludes,
5+ NumberIsInteger,
56 ObjectDefineProperty,
67 ReflectApply,
78 StringPrototypeIncludes,
@@ -19,6 +20,7 @@ const {
1920} = require ( 'internal/util/types' ) ;
2021
2122const {
23+ charIsSigned,
2224 getRawPointer,
2325 kFastArguments,
2426 kFastBufferInvoke,
@@ -28,6 +30,33 @@ const {
2830const kFastBuffer = Symbol ( 'kFastBuffer' ) ;
2931const kStringConversionBuffer = Symbol ( 'kStringConversionBuffer' ) ;
3032
33+ const U64_MAX = 0xFFFFFFFFFFFFFFFFn ;
34+ const I64_MAX = 0x7FFFFFFFFFFFFFFFn ;
35+ const I64_MIN = - 0x8000000000000000n ;
36+
37+ // These ranges mirror ToFFIArgument in src/ffi/types.cc. V8's Fast API
38+ // exposes narrow integers as 32-bit values and uses truncating BigInt
39+ // conversions, so the public FFI ranges must be checked before the raw call.
40+ const fastIntegerTypeInfo = {
41+ __proto__ : null ,
42+ i8 : { kind : 'number' , min : - 128 , max : 127 , label : 'an int8' } ,
43+ int8 : { kind : 'number' , min : - 128 , max : 127 , label : 'an int8' } ,
44+ char : charIsSigned ?
45+ { kind : 'number' , min : - 128 , max : 127 , label : 'an int8' } :
46+ { kind : 'number' , min : 0 , max : 255 , label : 'a uint8' } ,
47+ u8 : { kind : 'number' , min : 0 , max : 255 , label : 'a uint8' } ,
48+ uint8 : { kind : 'number' , min : 0 , max : 255 , label : 'a uint8' } ,
49+ bool : { kind : 'number' , min : 0 , max : 255 , label : 'a uint8' } ,
50+ i16 : { kind : 'number' , min : - 32768 , max : 32767 , label : 'an int16' } ,
51+ int16 : { kind : 'number' , min : - 32768 , max : 32767 , label : 'an int16' } ,
52+ u16 : { kind : 'number' , min : 0 , max : 65535 , label : 'a uint16' } ,
53+ uint16 : { kind : 'number' , min : 0 , max : 65535 , label : 'a uint16' } ,
54+ i64 : { kind : 'bigint' , min : I64_MIN , max : I64_MAX , label : 'an int64' } ,
55+ int64 : { kind : 'bigint' , min : I64_MIN , max : I64_MAX , label : 'an int64' } ,
56+ u64 : { kind : 'bigint' , min : 0n , max : U64_MAX , label : 'a uint64' } ,
57+ uint64 : { kind : 'bigint' , min : 0n , max : U64_MAX , label : 'a uint64' } ,
58+ } ;
59+
3160function throwFFIArgError ( msg ) {
3261 // eslint-disable-next-line no-restricted-syntax
3362 const err = new TypeError ( msg ) ;
@@ -40,6 +69,17 @@ function throwFFIArgCountError(expected, actual) {
4069 `Invalid argument count: expected ${ expected } , got ${ actual } ` ) ;
4170}
4271
72+ function validateFastIntegerArg ( type , value , index ) {
73+ const info = fastIntegerTypeInfo [ type ] ;
74+ if ( info === undefined ) return ;
75+ const validType = info . kind === 'number' ?
76+ typeof value === 'number' && NumberIsInteger ( value ) :
77+ typeof value === 'bigint' ;
78+ if ( ! validType || value < info . min || value > info . max ) {
79+ throwFFIArgError ( `Argument ${ index } must be ${ info . label } ` ) ;
80+ }
81+ }
82+
4383function needsRawPointerConversion ( type , rawFn ) {
4484 if ( rawFn !== undefined && rawFn [ kFastBuffer ] === true &&
4585 ( type === 'buffer' || type === 'arraybuffer' ) ) {
@@ -134,10 +174,11 @@ function convertPointerArg(type, value, owner, index) {
134174 return value ;
135175}
136176
137- function getPointerConversionIndexes ( argumentsTypes , rawFn ) {
177+ function getFastArgumentIndexes ( argumentsTypes , rawFn ) {
138178 let indexes = null ;
139179 for ( let i = 0 ; i < argumentsTypes . length ; i ++ ) {
140- if ( ! needsPointerConversion ( argumentsTypes [ i ] , rawFn ) ) {
180+ if ( fastIntegerTypeInfo [ argumentsTypes [ i ] ] === undefined &&
181+ ! needsPointerConversion ( argumentsTypes [ i ] , rawFn ) ) {
141182 continue ;
142183 }
143184 if ( indexes === null ) {
@@ -148,6 +189,12 @@ function getPointerConversionIndexes(argumentsTypes, rawFn) {
148189 return indexes ;
149190}
150191
192+ function convertFastArg ( type , value , rawFn , owner , index ) {
193+ validateFastIntegerArg ( type , value , index ) ;
194+ return needsPointerConversion ( type , rawFn ) ?
195+ convertPointerArg ( type , value , owner , index ) : value ;
196+ }
197+
151198function initializeFastBufferMetadata ( rawFn , argumentTypes ) {
152199 if ( rawFn === undefined || rawFn === null || argumentTypes === undefined ) {
153200 return ;
@@ -192,7 +239,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
192239 return rawFn ;
193240 }
194241
195- const indexes = getPointerConversionIndexes ( argumentTypes , rawFn ) ;
242+ const indexes = getFastArgumentIndexes ( argumentTypes , rawFn ) ;
196243 if ( indexes === null ) {
197244 return rawFn ;
198245 }
@@ -209,6 +256,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
209256 if ( arguments . length !== 1 ) {
210257 throwFFIArgCountError ( 1 , arguments . length ) ;
211258 }
259+ validateFastIntegerArg ( t0 , a0 , 0 ) ;
212260 let arg = a0 ;
213261 if ( needsNullPointerConversion ( t0 ) &&
214262 ( arg === null || arg === undefined ) ) {
@@ -232,8 +280,8 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
232280 if ( arguments . length !== 2 ) {
233281 throwFFIArgCountError ( 2 , arguments . length ) ;
234282 }
235- return rawFn ( c0 ? convertPointerArg ( t0 , a0 , owner , 0 ) : a0 ,
236- c1 ? convertPointerArg ( t1 , a1 , owner , 1 ) : a1 ) ;
283+ return rawFn ( c0 ? convertFastArg ( t0 , a0 , rawFn , owner , 0 ) : a0 ,
284+ c1 ? convertFastArg ( t1 , a1 , rawFn , owner , 1 ) : a1 ) ;
237285 } ;
238286 } else if ( nargs === 3 ) {
239287 const c0 = ArrayPrototypeIncludes ( indexes , 0 ) ;
@@ -246,9 +294,9 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
246294 if ( arguments . length !== 3 ) {
247295 throwFFIArgCountError ( 3 , arguments . length ) ;
248296 }
249- return rawFn ( c0 ? convertPointerArg ( t0 , a0 , owner , 0 ) : a0 ,
250- c1 ? convertPointerArg ( t1 , a1 , owner , 1 ) : a1 ,
251- c2 ? convertPointerArg ( t2 , a2 , owner , 2 ) : a2 ) ;
297+ return rawFn ( c0 ? convertFastArg ( t0 , a0 , rawFn , owner , 0 ) : a0 ,
298+ c1 ? convertFastArg ( t1 , a1 , rawFn , owner , 1 ) : a1 ,
299+ c2 ? convertFastArg ( t2 , a2 , rawFn , owner , 2 ) : a2 ) ;
252300 } ;
253301 } else {
254302 wrapper = function ( ...args ) {
@@ -257,8 +305,8 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
257305 }
258306 for ( let i = 0 ; i < indexes . length ; i ++ ) {
259307 const index = indexes [ i ] ;
260- args [ index ] = convertPointerArg (
261- argumentTypes [ index ] , args [ index ] , owner , index ) ;
308+ args [ index ] = convertFastArg (
309+ argumentTypes [ index ] , args [ index ] , rawFn , owner , index ) ;
262310 }
263311 return ReflectApply ( rawFn , undefined , args ) ;
264312 } ;
0 commit comments