diff options
| -rw-r--r-- | src/tools/miri/src/concurrency/data_race.rs | 12 | ||||
| -rw-r--r-- | src/tools/miri/src/concurrency/thread.rs | 41 | ||||
| -rw-r--r-- | src/tools/miri/src/concurrency/weak_memory.rs | 10 | ||||
| -rw-r--r-- | src/tools/miri/src/intptrcast.rs | 6 | ||||
| -rw-r--r-- | src/tools/miri/src/lib.rs | 2 | ||||
| -rw-r--r-- | src/tools/miri/src/machine.rs | 93 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/env.rs | 10 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/panic.rs | 11 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/time.rs | 16 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/tls.rs | 8 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/unix/fs.rs | 12 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/unix/linux/sync.rs | 52 | ||||
| -rw-r--r-- | src/tools/miri/src/shims/unix/sync.rs | 64 | ||||
| -rw-r--r-- | src/tools/miri/src/stacked_borrows/mod.rs | 19 | ||||
| -rw-r--r-- | src/tools/miri/src/tag_gc.rs | 172 |
15 files changed, 306 insertions, 222 deletions
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 2e54ddaaba1..d0fc349f1ac 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -696,6 +696,12 @@ pub struct VClockAlloc { alloc_ranges: RefCell<RangeMap<MemoryCellClocks>>, } +impl VisitTags for VClockAlloc { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) { + // No tags here. + } +} + impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation( @@ -1239,6 +1245,12 @@ pub struct GlobalState { pub track_outdated_loads: bool, } +impl VisitTags for GlobalState { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) { + // We don't have any tags. + } +} + impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 5e6fcbde69a..ec1da4138d4 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -32,7 +32,7 @@ pub enum SchedulingAction { /// Timeout callbacks can be created by synchronization primitives to tell the /// scheduler that they should be called once some period of time passes. -pub trait MachineCallback<'mir, 'tcx>: VisitMachineValues { +pub trait MachineCallback<'mir, 'tcx>: VisitTags { fn call(&self, ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>) -> InterpResult<'tcx>; } @@ -183,25 +183,21 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } } -impl VisitMachineValues for Thread<'_, '_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for Thread<'_, '_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { let Thread { panic_payload, last_error, stack, state: _, thread_name: _, join_status: _ } = self; - if let Some(payload) = panic_payload { - visit.visit(*payload); - } - if let Some(error) = last_error { - visit.visit(**error); - } + panic_payload.visit_tags(visit); + last_error.visit_tags(visit); for frame in stack { - frame.visit_machine_values(visit) + frame.visit_tags(visit) } } } -impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for Frame<'_, '_, Provenance, FrameData<'_>> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { let Frame { return_place, locals, @@ -210,21 +206,20 @@ impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> { instance: _, return_to_block: _, loc: _, + // There are some private fields we cannot access; they contain no tags. .. } = self; // Return place. - if let Place::Ptr(mplace) = **return_place { - visit.visit(mplace); - } + return_place.visit_tags(visit); // Locals. for local in locals.iter() { if let LocalValue::Live(value) = &local.value { - visit.visit(value); + value.visit_tags(visit); } } - extra.visit_machine_values(visit); + extra.visit_tags(visit); } } @@ -300,8 +295,8 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { } } -impl VisitMachineValues for ThreadManager<'_, '_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for ThreadManager<'_, '_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { let ThreadManager { threads, thread_local_alloc_ids, @@ -312,13 +307,13 @@ impl VisitMachineValues for ThreadManager<'_, '_> { } = self; for thread in threads { - thread.visit_machine_values(visit); + thread.visit_tags(visit); } - for ptr in thread_local_alloc_ids.borrow().values().copied() { - visit.visit(ptr); + for ptr in thread_local_alloc_ids.borrow().values() { + ptr.visit_tags(visit); } for callback in timeout_callbacks.values() { - callback.callback.visit_machine_values(visit); + callback.callback.visit_tags(visit); } } } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 15c6c8e9c0e..9d7a49c0b43 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -108,15 +108,15 @@ pub struct StoreBufferAlloc { store_buffers: RefCell<RangeObjectMap<StoreBuffer>>, } -impl VisitMachineValues for StoreBufferAlloc { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { - for val in self - .store_buffers +impl VisitTags for StoreBufferAlloc { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let Self { store_buffers } = self; + for val in store_buffers .borrow() .iter() .flat_map(|buf| buf.buffer.iter().map(|element| &element.val)) { - visit.visit(val); + val.visit_tags(visit); } } } diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs index b9e5def8fa7..9722b7643e4 100644 --- a/src/tools/miri/src/intptrcast.rs +++ b/src/tools/miri/src/intptrcast.rs @@ -44,6 +44,12 @@ pub struct GlobalStateInner { provenance_mode: ProvenanceMode, } +impl VisitTags for GlobalStateInner { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) { + // Nothing to visit here. + } +} + impl GlobalStateInner { pub fn new(config: &MiriConfig) -> Self { GlobalStateInner { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 245bdc51a8a..463feb4dcc8 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -112,7 +112,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; -pub use crate::tag_gc::{EvalContextExt as _, ProvenanceVisitor, VisitMachineValues}; +pub use crate::tag_gc::{EvalContextExt as _, VisitTags}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 523aad22aa5..20ae908fce8 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -63,13 +63,12 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> { } } -impl VisitMachineValues for FrameData<'_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { - let FrameData { catch_unwind, stacked_borrows: _, timing: _ } = self; +impl VisitTags for FrameData<'_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let FrameData { catch_unwind, stacked_borrows, timing: _ } = self; - if let Some(catch_unwind) = catch_unwind { - catch_unwind.visit_machine_values(visit); - } + catch_unwind.visit_tags(visit); + stacked_borrows.visit_tags(visit); } } @@ -261,17 +260,13 @@ pub struct AllocExtra { pub weak_memory: Option<weak_memory::AllocExtra>, } -impl VisitMachineValues for AllocExtra { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { - let AllocExtra { stacked_borrows, data_race: _, weak_memory } = self; - - if let Some(stacked_borrows) = stacked_borrows { - stacked_borrows.borrow().visit_machine_values(visit); - } +impl VisitTags for AllocExtra { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let AllocExtra { stacked_borrows, data_race, weak_memory } = self; - if let Some(weak_memory) = weak_memory { - weak_memory.visit_machine_values(visit); - } + stacked_borrows.visit_tags(visit); + data_race.visit_tags(visit); + weak_memory.visit_tags(visit); } } @@ -615,8 +610,9 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { } } -impl VisitMachineValues for MiriMachine<'_, '_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for MiriMachine<'_, '_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + #[rustfmt::skip] let MiriMachine { threads, tls, @@ -626,25 +622,52 @@ impl VisitMachineValues for MiriMachine<'_, '_> { cmd_line, extern_statics, dir_handler, - .. + stacked_borrows, + data_race, + intptrcast, + file_handler, + tcx: _, + isolated_op: _, + validate: _, + enforce_abi: _, + clock: _, + layouts: _, + static_roots: _, + profiler: _, + string_cache: _, + exported_symbols_cache: _, + panic_on_unsupported: _, + backtrace_style: _, + local_crates: _, + rng: _, + tracked_alloc_ids: _, + check_alignment: _, + cmpxchg_weak_failure_rate: _, + mute_stdout_stderr: _, + weak_memory: _, + preemption_rate: _, + report_progress: _, + basic_block_count: _, + #[cfg(unix)] + external_so_lib: _, + gc_interval: _, + since_gc: _, + num_cpus: _, } = self; - threads.visit_machine_values(visit); - tls.visit_machine_values(visit); - env_vars.visit_machine_values(visit); - dir_handler.visit_machine_values(visit); - - if let Some(argc) = argc { - visit.visit(argc); - } - if let Some(argv) = argv { - visit.visit(argv); - } - if let Some(cmd_line) = cmd_line { - visit.visit(cmd_line); - } - for ptr in extern_statics.values().copied() { - visit.visit(ptr); + threads.visit_tags(visit); + tls.visit_tags(visit); + env_vars.visit_tags(visit); + dir_handler.visit_tags(visit); + file_handler.visit_tags(visit); + data_race.visit_tags(visit); + stacked_borrows.visit_tags(visit); + intptrcast.visit_tags(visit); + argc.visit_tags(visit); + argv.visit_tags(visit); + cmd_line.visit_tags(visit); + for ptr in extern_statics.values() { + ptr.visit_tags(visit); } } } diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index d922014c383..076d3878de2 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -36,15 +36,13 @@ pub struct EnvVars<'tcx> { pub(crate) environ: Option<MPlaceTy<'tcx, Provenance>>, } -impl VisitMachineValues for EnvVars<'_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for EnvVars<'_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { let EnvVars { map, environ } = self; + environ.visit_tags(visit); for ptr in map.values() { - visit.visit(*ptr); - } - if let Some(env) = environ { - visit.visit(**env); + ptr.visit_tags(visit); } } } diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 0d681d3e09b..698e025961d 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -35,11 +35,12 @@ pub struct CatchUnwindData<'tcx> { ret: mir::BasicBlock, } -impl VisitMachineValues for CatchUnwindData<'_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { - let CatchUnwindData { catch_fn, data, dest: _, ret: _ } = self; - visit.visit(catch_fn); - visit.visit(data); +impl VisitTags for CatchUnwindData<'_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let CatchUnwindData { catch_fn, data, dest, ret: _ } = self; + catch_fn.visit_tags(visit); + data.visit_tags(visit); + dest.visit_tags(visit); } } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 05eff3dfd59..9f04034e1a1 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -219,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.register_timeout_callback( active_thread, Time::Monotonic(timeout_time), - Box::new(Callback { active_thread }), + Box::new(UnblockCallback { thread_to_unblock: active_thread }), ); Ok(0) @@ -242,24 +242,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.register_timeout_callback( active_thread, Time::Monotonic(timeout_time), - Box::new(Callback { active_thread }), + Box::new(UnblockCallback { thread_to_unblock: active_thread }), ); Ok(()) } } -struct Callback { - active_thread: ThreadId, +struct UnblockCallback { + thread_to_unblock: ThreadId, } -impl VisitMachineValues for Callback { - fn visit_machine_values(&self, _visit: &mut ProvenanceVisitor) {} +impl VisitTags for UnblockCallback { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) {} } -impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback { +impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for UnblockCallback { fn call(&self, ecx: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { - ecx.unblock_thread(self.active_thread); + ecx.unblock_thread(self.thread_to_unblock); Ok(()) } } diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 568eb6fa910..430dedbc170 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -235,15 +235,15 @@ impl<'tcx> TlsData<'tcx> { } } -impl VisitMachineValues for TlsData<'_> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for TlsData<'_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { let TlsData { keys, macos_thread_dtors, next_key: _, dtors_running: _ } = self; for scalar in keys.values().flat_map(|v| v.data.values()) { - visit.visit(scalar); + scalar.visit_tags(visit); } for (_, scalar) in macos_thread_dtors.values() { - visit.visit(scalar); + scalar.visit_tags(visit); } } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 5024b2ab45f..9713cd9265e 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -256,6 +256,12 @@ pub struct FileHandler { handles: BTreeMap<i32, Box<dyn FileDescriptor>>, } +impl VisitTags for FileHandler { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) { + // All our FileDescriptor do not have any tags. + } +} + impl FileHandler { pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box<dyn FileDescriptor>> = BTreeMap::new(); @@ -462,12 +468,12 @@ impl Default for DirHandler { } } -impl VisitMachineValues for DirHandler { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for DirHandler { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { let DirHandler { streams, next_id: _ } = self; for dir in streams.values() { - visit.visit(dir.entry); + dir.entry.visit_tags(visit); } } } diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index bbfb1c34db7..5762ee27b84 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -189,6 +189,31 @@ pub fn futex<'tcx>( // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. if let Some(timeout_time) = timeout_time { + struct Callback<'tcx> { + thread: ThreadId, + addr_usize: u64, + dest: PlaceTy<'tcx, Provenance>, + } + + impl<'tcx> VisitTags for Callback<'tcx> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let Callback { thread: _, addr_usize: _, dest } = self; + dest.visit_tags(visit); + } + } + + impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> { + fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { + this.unblock_thread(self.thread); + this.futex_remove_waiter(self.addr_usize, self.thread); + let etimedout = this.eval_libc("ETIMEDOUT")?; + this.set_last_error(etimedout)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), &self.dest)?; + + Ok(()) + } + } + let dest = dest.clone(); this.register_timeout_callback( thread, @@ -252,30 +277,3 @@ pub fn futex<'tcx>( Ok(()) } - -struct Callback<'tcx> { - thread: ThreadId, - addr_usize: u64, - dest: PlaceTy<'tcx, Provenance>, -} - -impl<'tcx> VisitMachineValues for Callback<'tcx> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { - let Callback { thread: _, addr_usize: _, dest } = self; - if let Place::Ptr(place) = **dest { - visit.visit(place); - } - } -} - -impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> { - fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { - this.unblock_thread(self.thread); - this.futex_remove_waiter(self.addr_usize, self.thread); - let etimedout = this.eval_libc("ETIMEDOUT")?; - this.set_last_error(etimedout)?; - this.write_scalar(Scalar::from_machine_isize(-1, this), &self.dest)?; - - Ok(()) - } -} diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 72b71ada8e0..5aafe76ade1 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -851,6 +851,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We return success for now and override it in the timeout callback. this.write_scalar(Scalar::from_i32(0), dest)?; + struct Callback<'tcx> { + active_thread: ThreadId, + mutex_id: MutexId, + id: CondvarId, + dest: PlaceTy<'tcx, Provenance>, + } + + impl<'tcx> VisitTags for Callback<'tcx> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let Callback { active_thread: _, mutex_id: _, id: _, dest } = self; + dest.visit_tags(visit); + } + } + + impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> { + fn call(&self, ecx: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { + // We are not waiting for the condvar any more, wait for the + // mutex instead. + reacquire_cond_mutex(ecx, self.active_thread, self.mutex_id)?; + + // Remove the thread from the conditional variable. + ecx.condvar_remove_waiter(self.id, self.active_thread); + + // Set the return value: we timed out. + let etimedout = ecx.eval_libc("ETIMEDOUT")?; + ecx.write_scalar(etimedout, &self.dest)?; + + Ok(()) + } + } + // Register the timeout callback. let dest = dest.clone(); this.register_timeout_callback( @@ -885,39 +916,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } -struct Callback<'tcx> { - active_thread: ThreadId, - mutex_id: MutexId, - id: CondvarId, - dest: PlaceTy<'tcx, Provenance>, -} - -impl<'tcx> VisitMachineValues for Callback<'tcx> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { - let Callback { active_thread: _, mutex_id: _, id: _, dest } = self; - if let Place::Ptr(place) = **dest { - visit.visit(place); - } - } -} - -impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> { - fn call(&self, ecx: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> { - // We are not waiting for the condvar any more, wait for the - // mutex instead. - reacquire_cond_mutex(ecx, self.active_thread, self.mutex_id)?; - - // Remove the thread from the conditional variable. - ecx.condvar_remove_waiter(self.id, self.active_thread); - - // Set the return value: we timed out. - let etimedout = ecx.eval_libc("ETIMEDOUT")?; - ecx.write_scalar(etimedout, &self.dest)?; - - Ok(()) - } -} - fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> { let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); let ty = tcx.bound_type_of(def_id).subst(*tcx, &[param.into()]); diff --git a/src/tools/miri/src/stacked_borrows/mod.rs b/src/tools/miri/src/stacked_borrows/mod.rs index b40358e2c15..829703d6562 100644 --- a/src/tools/miri/src/stacked_borrows/mod.rs +++ b/src/tools/miri/src/stacked_borrows/mod.rs @@ -71,6 +71,12 @@ pub struct FrameExtra { protected_tags: SmallVec<[SbTag; 2]>, } +impl VisitTags for FrameExtra { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) { + // `protected_tags` are fine to GC. + } +} + /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -109,6 +115,13 @@ pub struct GlobalStateInner { retag_fields: bool, } +impl VisitTags for GlobalStateInner { + fn visit_tags(&self, _visit: &mut dyn FnMut(SbTag)) { + // The only candidate is base_ptr_tags, and that does not need visiting since we don't ever + // GC the bottommost tag. + } +} + /// We need interior mutable access to the global state. pub type GlobalState = RefCell<GlobalStateInner>; @@ -513,10 +526,10 @@ impl Stacks { } } -impl VisitMachineValues for Stacks { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for Stacks { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { for tag in self.exposed_tags.iter().copied() { - visit.visit(tag); + visit(tag); } } } diff --git a/src/tools/miri/src/tag_gc.rs b/src/tools/miri/src/tag_gc.rs index e2273f055dd..5aa653632f3 100644 --- a/src/tools/miri/src/tag_gc.rs +++ b/src/tools/miri/src/tag_gc.rs @@ -2,123 +2,155 @@ use rustc_data_structures::fx::FxHashSet; use crate::*; -pub trait VisitMachineValues { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor); +pub trait VisitTags { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)); } -pub trait MachineValue { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>); +impl<T: VisitTags> VisitTags for Option<T> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + if let Some(x) = self { + x.visit_tags(visit); + } + } } -pub struct ProvenanceVisitor { - tags: FxHashSet<SbTag>, +impl<T: VisitTags> VisitTags for std::cell::RefCell<T> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + self.borrow().visit_tags(visit) + } } -impl ProvenanceVisitor { - pub fn visit<V>(&mut self, v: V) - where - V: MachineValue, - { - v.visit_provenance(&mut self.tags); +impl VisitTags for SbTag { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + visit(*self) } } -impl<T: MachineValue> MachineValue for &T { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { - (**self).visit_provenance(tags); +impl VisitTags for Provenance { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + if let Provenance::Concrete { sb, .. } = self { + visit(*sb); + } } } -impl MachineValue for Operand<Provenance> { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { +impl VisitTags for Pointer<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let (prov, _offset) = self.into_parts(); + prov.visit_tags(visit); + } +} + +impl VisitTags for Pointer<Option<Provenance>> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let (prov, _offset) = self.into_parts(); + prov.visit_tags(visit); + } +} + +impl VisitTags for Scalar<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { match self { - Operand::Immediate(Immediate::Scalar(s)) => { - s.visit_provenance(tags); - } - Operand::Immediate(Immediate::ScalarPair(s1, s2)) => { - s1.visit_provenance(tags); - s2.visit_provenance(tags); - } - Operand::Immediate(Immediate::Uninit) => {} - Operand::Indirect(p) => { - p.visit_provenance(tags); - } + Scalar::Ptr(ptr, _) => ptr.visit_tags(visit), + Scalar::Int(_) => (), } } } -impl MachineValue for Scalar<Provenance> { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { - if let Scalar::Ptr(ptr, _) = self { - if let Provenance::Concrete { sb, .. } = ptr.provenance { - tags.insert(sb); +impl VisitTags for Immediate<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + match self { + Immediate::Scalar(s) => { + s.visit_tags(visit); + } + Immediate::ScalarPair(s1, s2) => { + s1.visit_tags(visit); + s2.visit_tags(visit); } + Immediate::Uninit => {} } } } -impl MachineValue for MemPlace<Provenance> { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { - if let Some(Provenance::Concrete { sb, .. }) = self.ptr.provenance { - tags.insert(sb); +impl VisitTags for MemPlaceMeta<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + match self { + MemPlaceMeta::Meta(m) => m.visit_tags(visit), + MemPlaceMeta::None => {} } } } -impl MachineValue for SbTag { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { - tags.insert(*self); +impl VisitTags for MemPlace<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + let MemPlace { ptr, meta } = self; + ptr.visit_tags(visit); + meta.visit_tags(visit); } } -impl MachineValue for Pointer<Provenance> { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { - let (prov, _offset) = self.into_parts(); - if let Provenance::Concrete { sb, .. } = prov { - tags.insert(sb); +impl VisitTags for MPlaceTy<'_, Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + (**self).visit_tags(visit) + } +} + +impl VisitTags for Place<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + match self { + Place::Ptr(p) => p.visit_tags(visit), + Place::Local { .. } => { + // Will be visited as part of the stack frame. + } } } } -impl MachineValue for Pointer<Option<Provenance>> { - fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) { - let (prov, _offset) = self.into_parts(); - if let Some(Provenance::Concrete { sb, .. }) = prov { - tags.insert(sb); +impl VisitTags for PlaceTy<'_, Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + (**self).visit_tags(visit) + } +} + +impl VisitTags for Operand<Provenance> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { + match self { + Operand::Immediate(imm) => { + imm.visit_tags(visit); + } + Operand::Indirect(p) => { + p.visit_tags(visit); + } } } } -impl VisitMachineValues for Allocation<Provenance, AllocExtra> { - fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) { +impl VisitTags for Allocation<Provenance, AllocExtra> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { for (_size, prov) in self.provenance().iter() { - if let Provenance::Concrete { sb, .. } = prov { - visit.visit(*sb); - } + prov.visit_tags(visit); } - self.extra.visit_machine_values(visit); + self.extra.visit_tags(visit); } } -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { - /// GC helper to visit everything that can store provenance. The `ProvenanceVisitor` knows how - /// to extract provenance from the interpreter data types. - fn visit_all_machine_values(&self, acc: &mut ProvenanceVisitor) { - let this = self.eval_context_ref(); - +impl VisitTags for crate::MiriInterpCx<'_, '_> { + fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) { // Memory. - this.memory.alloc_map().iter(|it| { + self.memory.alloc_map().iter(|it| { for (_id, (_kind, alloc)) in it { - alloc.visit_machine_values(acc); + alloc.visit_tags(visit); } }); // And all the other machine values. - this.machine.visit_machine_values(acc); + self.machine.visit_tags(visit); } +} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // No reason to do anything at all if stacked borrows is off. @@ -126,9 +158,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { return Ok(()); } - let mut visitor = ProvenanceVisitor { tags: FxHashSet::default() }; - this.visit_all_machine_values(&mut visitor); - self.remove_unreachable_tags(visitor.tags); + let mut tags = FxHashSet::default(); + this.visit_tags(&mut |tag| { + tags.insert(tag); + }); + self.remove_unreachable_tags(tags); Ok(()) } |
