@@ -40,14 +40,27 @@ pub struct MemEvents {
4040/// A single memory access. 
4141#[ allow( dead_code) ]  
4242#[ cfg_attr( target_os = "linux" ,  derive( serde:: Serialize ,  serde:: Deserialize ) ) ]  
43- #[ derive( Debug ) ]  
43+ #[ derive( Clone ,   Debug ) ]  
4444pub  enum  AccessEvent  { 
4545    /// A read occurred on this memory range. 
4646     Read ( AccessRange ) , 
47- /// A read occurred on this memory range. 
47+      /// A read occurred on this memory range. 
4848     Write ( AccessRange ) , 
4949} 
5050
51+ impl  AccessEvent  { 
52+     fn  get_range ( & self )  -> AccessRange  { 
53+         match  self  { 
54+             AccessEvent :: Read ( access_range)  => access_range. clone ( ) , 
55+             AccessEvent :: Write ( access_range)  => access_range. clone ( ) , 
56+         } 
57+     } 
58+ 
59+     fn  is_read ( & self )  -> bool  { 
60+         matches ! ( self ,  AccessEvent :: Read ( _) ) 
61+     } 
62+ } 
63+ 
5164/// The memory touched by a given access. 
5265#[ allow( dead_code) ]  
5366#[ cfg_attr( target_os = "linux" ,  derive( serde:: Serialize ,  serde:: Deserialize ) ) ]  
@@ -198,6 +211,52 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
198211        } 
199212        None 
200213    } 
214+ 
215+     /// Applies the `events` to Miri's internal state. The event vector must be 
216+      /// ordered sequentially by when the accesses happened, and the sizes are 
217+      /// assumed to be exact. 
218+      fn  tracing_apply_accesses ( & mut  self ,  events :  MemEvents )  -> InterpResult < ' tcx >  { 
219+         let  this = self . eval_context_mut ( ) ; 
220+ 
221+         for  evt in  events. acc_events  { 
222+             let  evt_rg = evt. get_range ( ) ; 
223+             // We're assuming an access only touches 1 allocation. 
224+             let  alloc_id = this
225+                 . alloc_id_from_addr ( evt_rg. addr . to_u64 ( ) ,  evt_rg. size . try_into ( ) . unwrap ( ) ,  true ) 
226+                 . expect ( "Foreign code did an out-of-bounds access!" ) ; 
227+ 
228+             // Get the (size, len) pair for the current allocation. 
229+             let  ( alloc_addr,  alloc_len)  = { 
230+                 let  alloc = this. get_alloc_raw ( alloc_id) ?; 
231+                 ( alloc. get_bytes_unchecked_raw ( ) . addr ( ) ,  alloc. len ( ) ) 
232+             } ; 
233+ 
234+             let  unshifted_overlap = std:: cmp:: max ( evt_rg. addr ,  alloc_addr) 
235+                 ..std:: cmp:: min ( 
236+                     evt_rg. addr . strict_add ( evt_rg. size ) , 
237+                     alloc_addr. strict_add ( alloc_len) , 
238+                 ) ; 
239+             // Shift the overlap range to be an offset from the allocation base addr. 
240+             let  overlap = unshifted_overlap. start . strict_sub ( alloc_addr) 
241+                 ..unshifted_overlap. end . strict_sub ( alloc_addr) ; 
242+ 
243+             if  evt. is_read ( )  { 
244+                 let  alloc = this. get_alloc_raw ( alloc_id) ?; 
245+                 let  p_map = alloc. provenance ( ) ; 
246+                 for  idx in  overlap { 
247+                     // If a provenance was read by the foreign code, expose it. 
248+                     if  let  Some ( prov)  = p_map. get ( Size :: from_bytes ( idx) ,  this)  { 
249+                         this. expose_provenance ( prov) ?; 
250+                     } 
251+                 } 
252+             }  else  { 
253+                 let  ( _alloc_mut,  _m)  = this. get_alloc_raw_mut ( alloc_id) ?; 
254+                 // TODO: expose a way to write wildcards on a given range and mark it as init 
255+             } 
256+         } 
257+ 
258+         interp_ok ( ( ) ) 
259+     } 
201260} 
202261
203262impl < ' tcx >  EvalContextExt < ' tcx >  for  crate :: MiriInterpCx < ' tcx >  { } 
@@ -223,6 +282,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
223282            } 
224283        } ; 
225284
285+         // Do we have ptrace? 
286+         let  tracing = trace:: Supervisor :: is_enabled ( ) ; 
287+ 
226288        // Get the function arguments, and convert them to `libffi`-compatible form. 
227289        let  mut  libffi_args = Vec :: < CArg > :: with_capacity ( args. len ( ) ) ; 
228290        for  arg in  args. iter ( )  { 
@@ -242,9 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
242304                // The first time this happens, print a warning. 
243305                if  !this. machine . native_call_mem_warned . replace ( true )  { 
244306                    // Newly set, so first time we get here. 
245-                     this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem  { 
246-                         tracing :  self :: trace:: Supervisor :: is_enabled ( ) , 
247-                     } ) ; 
307+                     this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem  {  tracing } ) ; 
248308                } 
249309
250310                this. expose_provenance ( prov) ?; 
@@ -270,15 +330,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
270330            // be read by FFI. The `black_box` is defensive programming as LLVM likes 
271331            // to (incorrectly) optimize away ptr2int casts whose result is unused. 
272332            std:: hint:: black_box ( alloc. get_bytes_unchecked_raw ( ) . expose_provenance ( ) ) ; 
273-             // Expose all provenances in this allocation, since the native code can do $whatever. 
274-             for  prov in  alloc. provenance ( ) . provenances ( )  { 
275-                 this. expose_provenance ( prov) ?; 
333+ 
334+             if  !tracing { 
335+                 // Expose all provenances in this allocation, since the native code can do $whatever. 
336+                 for  prov in  alloc. provenance ( ) . provenances ( )  { 
337+                     this. expose_provenance ( prov) ?; 
338+                 } 
276339            } 
277340
278341            // Prepare for possible write from native code if mutable. 
279342            if  info. mutbl . is_mut ( )  { 
280-                 let  alloc = & mut  this. get_alloc_raw_mut ( alloc_id) ?. 0 ; 
281-                 alloc. prepare_for_native_access ( ) ; 
343+                 let  alloc = this. get_alloc_raw_mut ( alloc_id) ?. 0 ; 
344+                 if  tracing { 
345+                     let  full_range =
346+                         AllocRange  {  start :  Size :: ZERO ,  size :  Size :: from_bytes ( alloc. len ( ) )  } ; 
347+                     // Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be. 
348+                     for  chunk in  alloc. init_mask ( ) . clone ( ) . range_as_init_chunks ( full_range)  { 
349+                         if  !chunk. is_init ( )  { 
350+                             let  uninit_bytes = unsafe  { 
351+                                 let  start = chunk. range ( ) . start . bytes_usize ( ) ; 
352+                                 let  len = chunk. range ( ) . end . bytes_usize ( ) . strict_sub ( start) ; 
353+                                 let  ptr = alloc. get_bytes_unchecked_raw_mut ( ) . add ( start) ; 
354+                                 std:: slice:: from_raw_parts_mut ( ptr,  len) 
355+                             } ; 
356+                             uninit_bytes. fill ( 0 ) ; 
357+                         } 
358+                     } 
359+                 }  else  { 
360+                     // FIXME: Make this take an arg to determine whether it actually 
361+                     // writes wildcard prov & marks init, so we don't duplicate code above. 
362+                     alloc. prepare_for_native_access ( ) ; 
363+                 } 
282364                // Also expose *mutable* provenance for the interpreter-level allocation. 
283365                std:: hint:: black_box ( alloc. get_bytes_unchecked_raw_mut ( ) . expose_provenance ( ) ) ; 
284366            } 
@@ -290,10 +372,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
290372        let  ( ret,  maybe_memevents)  =
291373            this. call_native_with_args ( link_name,  dest,  code_ptr,  libffi_args) ?; 
292374
293-         if  cfg ! ( target_os = "linux" ) 
294-             && let  Some ( events)  = maybe_memevents
295-         { 
296-             trace ! ( "Registered FFI events:\n {events:#0x?}" ) ; 
375+         if  tracing { 
376+             this. tracing_apply_accesses ( maybe_memevents. unwrap ( ) ) ?; 
297377        } 
298378
299379        this. write_immediate ( * ret,  dest) ?; 
0 commit comments