11//! Implements calling functions from a native library.
22
3+ use std:: cell:: Cell ;
34use std:: ops:: Deref ;
45use std:: os:: raw:: c_void;
6+ use std:: ptr:: NonNull ;
57use std:: sync:: atomic:: AtomicBool ;
68
79use libffi:: low:: CodePtr ;
@@ -17,6 +19,10 @@ use self::helpers::ToSoft;
1719
1820mod ffi;
1921
22+ thread_local ! {
23+ static INTERP_CTX : Cell <Option <NonNull <c_void>>> = const { Cell :: new( None ) } ;
24+ }
25+
2026#[ cfg_attr(
2127 not( all(
2228 target_os = "linux" ,
@@ -28,6 +34,7 @@ mod ffi;
2834pub mod trace;
2935
3036use self :: ffi:: OwnedArg ;
37+ use crate :: diagnostics:: DiagLevel ;
3138use crate :: * ;
3239
3340/// The final results of an FFI trace, containing every relevant event detected
@@ -95,6 +102,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
95102 trace:: Supervisor :: do_ffi ( alloc, || {
96103 // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
97104 // as the specified primitive integer type
105+ INTERP_CTX . set ( NonNull :: new (
106+ ( this as * const MiriInterpCx < ' tcx > as * mut MiriInterpCx < ' tcx > ) . cast ( ) ,
107+ ) ) ;
98108 let scalar = match dest. layout . ty . kind ( ) {
99109 // ints
100110 ty:: Int ( IntTy :: I8 ) => {
@@ -455,21 +465,21 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
455465pub fn build_libffi_closure < ' tcx , ' this > (
456466 this : & ' this MiriInterpCx < ' tcx > ,
457467 fn_ptr : rustc_middle:: ty:: FnSig < ' tcx > ,
458- ) -> InterpResult < ' tcx , Option < libffi:: middle:: Closure < ' this > > > {
468+ ) -> Option < libffi:: middle:: Closure < ' this > > {
459469 let mut args = Vec :: new ( ) ;
460470 for input in fn_ptr. inputs ( ) . iter ( ) {
461471 let layout = match this. layout_of ( * input) {
462472 Ok ( layout) => layout,
463473 Err ( e) => {
464474 tracing:: info!( ?e, "Skip closure" ) ;
465- return interp_ok ( None ) ;
475+ return None ;
466476 }
467477 } ;
468478 let ty = match this. ty_to_ffitype ( layout) . report_err ( ) {
469479 Ok ( ty) => ty,
470480 Err ( e) => {
471481 tracing:: info!( ?e, "Skip closure" ) ;
472- return interp_ok ( None ) ;
482+ return None ;
473483 }
474484 } ;
475485 args. push ( ty) ;
@@ -480,27 +490,22 @@ pub fn build_libffi_closure<'tcx, 'this>(
480490 Ok ( layout) => layout,
481491 Err ( e) => {
482492 tracing:: info!( ?e, "Skip closure" ) ;
483- return interp_ok ( None ) ;
493+ return None ;
484494 }
485495 } ;
486496 match this. ty_to_ffitype ( layout) . report_err ( ) {
487497 Ok ( ty) => ty,
488498 Err ( e) => {
489499 tracing:: info!( ?e, "Skip closure" ) ;
490- return interp_ok ( None ) ;
500+ return None ;
491501 }
492502 }
493503 } ;
494504 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- } ;
505+ let data = CallbackData { } ;
501506 let data = Box :: leak ( Box :: new ( data) ) ;
502507 let closure = closure_builder. into_closure ( callback_callback, data) ;
503- interp_ok ( Some ( closure) )
508+ Some ( closure)
504509}
505510
506511impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -596,44 +601,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
596601 }
597602}
598603
599- struct CallbackData < ' a , ' tcx > {
600- args : Vec < Ty < ' tcx > > ,
601- #[ expect( dead_code, reason = "It's there for later" ) ]
602- result : Ty < ' tcx > ,
603- this : & ' a MiriInterpCx < ' tcx > ,
604- }
604+ struct CallbackData { }
605605
606606unsafe extern "C" fn callback_callback (
607- cif : & libffi:: low:: ffi_cif ,
607+ _cif : & libffi:: low:: ffi_cif ,
608608 _result : & mut c_void ,
609- args : * const * const c_void ,
610- infos : & CallbackData < ' _ , ' _ > ,
609+ _args : * const * const c_void ,
610+ _infos : & CallbackData ,
611611) {
612- debug_assert_eq ! ( cif. nargs. try_into( ) , Ok ( infos. args. len( ) ) ) ;
613- let mut rust_args = Vec :: with_capacity ( infos. args . len ( ) ) ;
614- // We cast away the pointer to pointer to get a pointer to the actual argument
615- let mut args = args. cast :: < c_void > ( ) ;
616- for arg in & infos. args {
617- let scalar = match arg. kind ( ) {
618- ty:: RawPtr ( ..) => {
619- let ptr = StrictPointer :: new ( Provenance :: Wildcard , Size :: from_bytes ( args. addr ( ) ) ) ;
620- // This offset moves the pointer to the next argument
621- args = unsafe { args. offset ( 1 ) } ;
622- Scalar :: from_pointer ( ptr, infos. this )
623- }
624- // the other types
625- _ => todo ! ( ) ,
626- } ;
627- rust_args. push ( scalar) ;
612+ if let Some ( this) = INTERP_CTX . get ( ) {
613+ let ctx = unsafe { this. cast :: < MiriInterpCx < ' _ > > ( ) . as_ref ( ) } ;
614+ let stacktrace = ctx. generate_stacktrace ( ) ;
615+ crate :: diagnostics:: report_msg (
616+ DiagLevel :: Error ,
617+ "tried to call a function pointer through the FFI boundary" . into ( ) ,
618+ vec ! [ "this function called a function pointer calling back into Rust" . into( ) ] ,
619+ vec ! [ ( None , "this is not supported yet by miri" . into( ) ) ] ,
620+ Vec :: new ( ) ,
621+ & stacktrace,
622+ None ,
623+ & ctx. machine ,
624+ ) ;
625+ } else {
626+ // There is no interpctx set which likely means we are running in a different thread
627+ // than that one that called into the native library. At this point we fall back
628+ // to just reporting an error via eprintln before aborting.
629+ eprintln ! (
630+ "Tried to call a function pointer via FFI boundary. \
631+ That's not supported yet by miri"
632+ ) ;
628633 }
629-
630634 // We abort the execution at this point as we cannot return the
631635 // 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- ) ;
638636 std:: process:: exit ( 1 ) ;
639637}
0 commit comments