11//! Implements calling functions from a native library.
22
3- use std:: borrow:: Cow ;
4- use std:: cell:: RefCell ;
53use std:: ops:: Deref ;
64use std:: os:: raw:: c_void;
75use std:: sync:: atomic:: AtomicBool ;
@@ -19,14 +17,6 @@ use self::helpers::ToSoft;
1917
2018mod ffi;
2119
22- struct CallbackError {
23- message : Cow < ' static , str > ,
24- }
25-
26- thread_local ! {
27- pub static CALLBACK_MESSAGES : RefCell <Vec <CallbackError >> = RefCell :: new( Vec :: new( ) ) ;
28- }
29-
3020#[ cfg_attr(
3121 not( all(
3222 target_os = "linux" ,
@@ -103,8 +93,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
10393 let alloc = ( ) ;
10494
10595 trace:: Supervisor :: do_ffi ( alloc, || {
106- // clear the callback error buffer
107- CALLBACK_MESSAGES . with_borrow_mut ( |c| c. clear ( ) ) ;
10896 // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
10997 // as the specified primitive integer type
11098 let scalar = match dest. layout . ty . kind ( ) {
@@ -179,11 +167,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
179167 ) )
180168 . into ( ) ,
181169 } ;
182- let callback_error_messages = CALLBACK_MESSAGES . take ( ) ;
183- if !callback_error_messages. is_empty ( ) {
184- let first = callback_error_messages. first ( ) . unwrap ( ) ;
185- return Err ( err_unsup_format ! ( "{}" , first. message) ) . into ( ) ;
186- }
187170 interp_ok ( ImmTy :: from_scalar ( scalar, dest. layout ) )
188171 } )
189172 }
@@ -303,12 +286,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
303286
304287 /// Extract the value from the result of reading an operand from the machine
305288 /// and convert it to a `OwnedArg`.
306- fn op_to_ffi_arg (
307- & self ,
308- v : & OpTy < ' tcx > ,
309- tracing : bool ,
310- link_name : & Symbol ,
311- ) -> InterpResult < ' tcx , OwnedArg > {
289+ fn op_to_ffi_arg ( & self , v : & OpTy < ' tcx > , tracing : bool ) -> InterpResult < ' tcx , OwnedArg > {
312290 let this = self . eval_context_ref ( ) ;
313291
314292 // This should go first so that we emit unsupported before doing a bunch
@@ -333,44 +311,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
333311 // casting the integer in `byte` to a pointer and using that.
334312 let bytes = match v. as_mplace_or_imm ( ) {
335313 either:: Either :: Left ( mplace) => {
336- let ptr_overwrite = match v. layout . ty . kind ( ) {
337- ty:: Adt ( _adt_def, args) =>
338- if let ty:: FnPtr ( fn_ptr, _header) = args. type_at ( 0 ) . kind ( ) {
339- let args = fn_ptr
340- . skip_binder ( )
341- . inputs ( )
342- . into_iter ( )
343- . map ( |i| {
344- let layout = this. layout_of ( i. clone ( ) ) ?;
345- this. ty_to_ffitype ( layout)
346- } )
347- . collect :: < InterpResult < ' _ , Vec < _ > > > ( ) ?;
348- let res_type = fn_ptr. skip_binder ( ) . output ( ) ;
349- let res_type = {
350- let layout = this. layout_of ( res_type) ?;
351- this. ty_to_ffitype ( layout) ?
352- } ;
353- let closure_builder = libffi:: middle:: Builder :: new ( )
354- . args ( args)
355- . res ( res_type)
356- . abi ( libffi:: raw:: ffi_abi_FFI_UNIX64) ;
357- let data = CallbackData {
358- args : fn_ptr. skip_binder ( ) . inputs ( ) . to_vec ( ) ,
359- result : fn_ptr. skip_binder ( ) . output ( ) ,
360- this,
361- link_name : link_name. clone ( ) ,
362- ty : v. layout . ty ,
363- } ;
364- // todo: leaking is likely not optimal here
365- let data = Box :: leak ( Box :: new ( data) ) ;
366-
367- let closure = closure_builder. into_closure ( callback_callback, data) ;
368- Some ( closure)
369- } else {
370- None
371- } ,
372- _ => None ,
373- } ;
374314 // Get the alloc id corresponding to this mplace, alongside
375315 // a pointer that's offset to point to this particular
376316 // mplace (not one at the base addr of the allocation).
@@ -393,33 +333,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
393333 // is kind of outside the interpreter, after all...
394334 let ret: Box < [ u8 ] > =
395335 Box :: from ( alloc. inspect_with_uninit_and_ptr_outside_interpreter ( range) ) ;
396- if ret. iter ( ) . any ( |b| * b != 0 )
397- && let Some ( ptr_overwrite) = ptr_overwrite
398- {
399- // we need to leak the closure here as we don't know when it's actually called
400- // I'm not sure if it's possible to have a better solution for that
401- let ptr_overwrite = Box :: leak ( Box :: new ( ptr_overwrite) ) ;
402-
403- // we get a **reference** to a function ptr here
404- // (The actual argument type doesn't matter)
405- let ptr = unsafe {
406- ptr_overwrite. instantiate_code_ptr :: < unsafe extern "C" fn ( * const c_void ) > ( )
407- } ;
408- // so deref away the reference
409- let ptr = * ptr;
410- // cast it to void as the actual function type doesn't matter
411- let ptr = ptr as * const c_void ;
412- // get a the address as usize to write it into the
413- // right memory location
414- let bytes = ptr. addr ( ) ;
415- // bytes are in native endian, as that's literally
416- // the definition of native endian
417- let bytes = usize:: to_ne_bytes ( bytes) ;
418- // return the bytes of the ptr
419- Box :: from ( bytes)
420- } else {
421- ret
422- }
336+ ret
423337 }
424338 either:: Either :: Right ( imm) => {
425339 let mut bytes: Box < [ u8 ] > = vec ! [ 0 ; imm. layout. size. bytes_usize( ) ] . into ( ) ;
@@ -538,6 +452,57 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
538452 }
539453}
540454
455+ pub fn build_libffi_closure < ' tcx , ' this > (
456+ this : & ' this MiriInterpCx < ' tcx > ,
457+ fn_ptr : rustc_middle:: ty:: FnSig < ' tcx > ,
458+ ) -> InterpResult < ' tcx , Option < libffi:: middle:: Closure < ' this > > > {
459+ let mut args = Vec :: new ( ) ;
460+ for input in fn_ptr. inputs ( ) . iter ( ) {
461+ let layout = match this. layout_of ( * input) {
462+ Ok ( layout) => layout,
463+ Err ( e) => {
464+ tracing:: info!( ?e, "Skip closure" ) ;
465+ return interp_ok ( None ) ;
466+ }
467+ } ;
468+ let ty = match this. ty_to_ffitype ( layout) . report_err ( ) {
469+ Ok ( ty) => ty,
470+ Err ( e) => {
471+ tracing:: info!( ?e, "Skip closure" ) ;
472+ return interp_ok ( None ) ;
473+ }
474+ } ;
475+ args. push ( ty) ;
476+ }
477+ let res_type = fn_ptr. output ( ) ;
478+ let res_type = {
479+ let layout = match this. layout_of ( res_type) {
480+ Ok ( layout) => layout,
481+ Err ( e) => {
482+ tracing:: info!( ?e, "Skip closure" ) ;
483+ return interp_ok ( None ) ;
484+ }
485+ } ;
486+ match this. ty_to_ffitype ( layout) . report_err ( ) {
487+ Ok ( ty) => ty,
488+ Err ( e) => {
489+ tracing:: info!( ?e, "Skip closure" ) ;
490+ return interp_ok ( None ) ;
491+ }
492+ }
493+ } ;
494+ let closure_builder = libffi:: middle:: Builder :: new ( ) . args ( args) . res ( res_type) ;
495+ let data = CallbackData {
496+ args : fn_ptr. inputs ( ) . to_vec ( ) ,
497+ result : fn_ptr. output ( ) ,
498+ this,
499+ //link_name: *link_name,
500+ } ;
501+ let data = Box :: leak ( Box :: new ( data) ) ;
502+ let closure = closure_builder. into_closure ( callback_callback, data) ;
503+ interp_ok ( Some ( closure) )
504+ }
505+
541506impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
542507pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
543508 /// Call the native host function, with supplied arguments.
@@ -567,7 +532,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
567532 // Get the function arguments, copy them, and prepare the type descriptions.
568533 let mut libffi_args = Vec :: < OwnedArg > :: with_capacity ( args. len ( ) ) ;
569534 for arg in args. iter ( ) {
570- libffi_args. push ( this. op_to_ffi_arg ( arg, tracing, & link_name ) ?) ;
535+ libffi_args. push ( this. op_to_ffi_arg ( arg, tracing) ?) ;
571536 }
572537
573538 // Prepare all exposed memory (both previously exposed, and just newly exposed since a
@@ -633,26 +598,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
633598
634599struct CallbackData < ' a , ' tcx > {
635600 args : Vec < Ty < ' tcx > > ,
601+ #[ expect( dead_code, reason = "It's there for later" ) ]
636602 result : Ty < ' tcx > ,
637603 this : & ' a MiriInterpCx < ' tcx > ,
638- link_name : Symbol ,
639- ty : Ty < ' tcx > ,
640604}
641605
642606unsafe extern "C" fn callback_callback (
643607 cif : & libffi:: low:: ffi_cif ,
644- result : & mut c_void ,
608+ _result : & mut c_void ,
645609 args : * const * const c_void ,
646610 infos : & CallbackData < ' _ , ' _ > ,
647611) {
648- debug_assert_eq ! ( cif. nargs as usize , infos. args. len( ) ) ;
612+ debug_assert_eq ! ( cif. nargs. try_into ( ) , Ok ( infos. args. len( ) ) ) ;
649613 let mut rust_args = Vec :: with_capacity ( infos. args . len ( ) ) ;
650- // cast away the pointer to pointer
651- let mut args = args as * const c_void ;
614+ // We cast away the pointer to pointer to get a pointer to the actual argument
615+ let mut args = args. cast :: < c_void > ( ) ;
652616 for arg in & infos. args {
653617 let scalar = match arg. kind ( ) {
654618 ty:: RawPtr ( ..) => {
655619 let ptr = StrictPointer :: new ( Provenance :: Wildcard , Size :: from_bytes ( args. addr ( ) ) ) ;
620+ // This offset moves the pointer to the next argument
656621 args = unsafe { args. offset ( 1 ) } ;
657622 Scalar :: from_pointer ( ptr, infos. this )
658623 }
@@ -662,60 +627,13 @@ unsafe extern "C" fn callback_callback(
662627 rust_args. push ( scalar) ;
663628 }
664629
665- CALLBACK_MESSAGES . with_borrow_mut ( |msgs| {
666- msgs. push ( CallbackError {
667- message : format ! ( "Tried to call a function pointer via FFI boundary. \
668- That's not supported yet by miri\n This function pointer was registered by a call to `{}` \
669- using an argument of the type `{}`", infos. link_name, infos. ty)
670- . into ( ) ,
671- } ) ;
672- } ) ;
673-
674- // write here the output
675- // For now we just try to write some dummy output
676- // by using some "reasonable" default values
677- // to prevent crashing
678- match infos. result . kind ( ) {
679- ty:: RawPtr ( ..) => {
680- write_helper :: < * mut c_void > ( result, std:: ptr:: null_mut ( ) ) ;
681- }
682- ty:: Int ( IntTy :: I8 ) => {
683- write_helper :: < i8 > ( result, 0 ) ;
684- }
685- ty:: Int ( IntTy :: I16 ) => {
686- write_helper :: < i32 > ( result, 0 ) ;
687- }
688- ty:: Int ( IntTy :: I32 ) => {
689- write_helper :: < i32 > ( result, 0 ) ;
690- }
691- ty:: Int ( IntTy :: I64 ) => {
692- write_helper :: < i64 > ( result, 0 ) ;
693- }
694- ty:: Int ( IntTy :: Isize ) => {
695- write_helper :: < isize > ( result, 0 ) ;
696- }
697- ty:: Uint ( UintTy :: U8 ) => {
698- write_helper :: < u8 > ( result, 0 ) ;
699- }
700- ty:: Uint ( UintTy :: U16 ) => {
701- write_helper :: < u16 > ( result, 0 ) ;
702- }
703- ty:: Uint ( UintTy :: U32 ) => {
704- write_helper :: < u32 > ( result, 0 ) ;
705- }
706- ty:: Uint ( UintTy :: U64 ) => {
707- write_helper :: < u64 > ( result, 0 ) ;
708- }
709- ty:: Uint ( UintTy :: Usize ) => {
710- write_helper :: < usize > ( result, 0 ) ;
711- }
712- // unsure how to handle that at allow
713- // Just do nothing for now?
714- _ => { }
715- } ;
716- }
717-
718- fn write_helper < T > ( ptr : & mut c_void , value : T ) {
719- let ptr = ( ptr as * mut c_void ) as * mut T ;
720- unsafe { std:: ptr:: write ( ptr, value) } ;
630+ // We abort the execution at this point as we cannot return the
631+ // expected value here.
632+ eprintln ! (
633+ "Tried to call a function pointer via FFI boundary. \
634+ That's not supported yet by miri\n This function pointer was registered by a call to `{}` \
635+ using an argument of the type `{}`",
636+ "todo: fill in name" , "todo: fill in type"
637+ ) ;
638+ std:: process:: exit ( 1 ) ;
721639}
0 commit comments