@@ -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