Skip to content

Commit 25e8f8e

Browse files
saethlinRalfJung
authored andcommitted
Expand VisitMachineValues to cover more pointers in the interpreter
1 parent 17cb715 commit 25e8f8e

File tree

10 files changed

+156
-33
lines changed

10 files changed

+156
-33
lines changed

src/tools/miri/src/concurrency/range_object_map.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ impl<T> RangeObjectMap<T> {
132132
pub fn remove_from_pos(&mut self, pos: Position) {
133133
self.v.remove(pos);
134134
}
135+
136+
pub fn iter(&self) -> impl Iterator<Item = &T> {
137+
self.v.iter().map(|e| &e.data)
138+
}
135139
}
136140

137141
impl<T> Index<Position> for RangeObjectMap<T> {

src/tools/miri/src/concurrency/thread.rs

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,41 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
181181
}
182182
}
183183

184+
impl VisitMachineValues for Thread<'_, '_> {
185+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
186+
let Thread { panic_payload, last_error, stack, .. } = self;
187+
188+
if let Some(payload) = panic_payload {
189+
visit(&Operand::Immediate(Immediate::Scalar(*payload)))
190+
}
191+
if let Some(error) = last_error {
192+
visit(&Operand::Indirect(**error))
193+
}
194+
for frame in stack {
195+
frame.visit_machine_values(visit)
196+
}
197+
}
198+
}
199+
200+
impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> {
201+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
202+
let Frame { return_place, locals, extra, .. } = self;
203+
204+
// Return place.
205+
if let Place::Ptr(mplace) = **return_place {
206+
visit(&Operand::Indirect(mplace));
207+
}
208+
// Locals.
209+
for local in locals.iter() {
210+
if let LocalValue::Live(value) = &local.value {
211+
visit(value);
212+
}
213+
}
214+
215+
extra.visit_machine_values(visit);
216+
}
217+
}
218+
184219
/// A specific moment in time.
185220
#[derive(Debug)]
186221
pub enum Time {
@@ -253,6 +288,22 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
253288
}
254289
}
255290

291+
impl VisitMachineValues for ThreadManager<'_, '_> {
292+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
293+
let ThreadManager { threads, thread_local_alloc_ids, .. } = self;
294+
295+
for thread in threads {
296+
thread.visit_machine_values(visit);
297+
}
298+
for ptr in thread_local_alloc_ids.borrow().values().copied() {
299+
let ptr: Pointer<Option<Provenance>> = ptr.into();
300+
visit(&Operand::Indirect(MemPlace::from_ptr(ptr)));
301+
}
302+
// FIXME: Do we need to do something for TimeoutCallback? That's a Box<dyn>, not sure what
303+
// to do.
304+
}
305+
}
306+
256307
impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
257308
pub(crate) fn init(ecx: &mut MiriInterpCx<'mir, 'tcx>) {
258309
if ecx.tcx.sess.target.os.as_ref() != "windows" {
@@ -625,33 +676,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
625676
}
626677
}
627678

628-
impl VisitMachineValues for ThreadManager<'_, '_> {
629-
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
630-
// FIXME some other fields also contain machine values
631-
let ThreadManager { threads, .. } = self;
632-
633-
for thread in threads {
634-
// FIXME: implement VisitMachineValues for `Thread` and `Frame` instead.
635-
// In particular we need to visit the `last_error` and `catch_unwind` fields.
636-
if let Some(payload) = thread.panic_payload {
637-
visit(&Operand::Immediate(Immediate::Scalar(payload)))
638-
}
639-
for frame in &thread.stack {
640-
// Return place.
641-
if let Place::Ptr(mplace) = *frame.return_place {
642-
visit(&Operand::Indirect(mplace));
643-
}
644-
// Locals.
645-
for local in frame.locals.iter() {
646-
if let LocalValue::Live(value) = &local.value {
647-
visit(value);
648-
}
649-
}
650-
}
651-
}
652-
}
653-
}
654-
655679
// Public interface to thread management.
656680
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
657681
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

src/tools/miri/src/concurrency/weak_memory.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ pub struct StoreBufferAlloc {
108108
store_buffers: RefCell<RangeObjectMap<StoreBuffer>>,
109109
}
110110

111+
impl StoreBufferAlloc {
112+
pub fn iter(&self, mut visitor: impl FnMut(&Scalar<Provenance>)) {
113+
for val in self
114+
.store_buffers
115+
.borrow()
116+
.iter()
117+
.flat_map(|buf| buf.buffer.iter().map(|element| &element.val))
118+
{
119+
visitor(val)
120+
}
121+
}
122+
}
123+
111124
#[derive(Debug, Clone, PartialEq, Eq)]
112125
pub(super) struct StoreBuffer {
113126
// Stores to this location in modification order

src/tools/miri/src/machine.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
6363
}
6464
}
6565

66+
impl VisitMachineValues for FrameData<'_> {
67+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
68+
let FrameData { catch_unwind, .. } = self;
69+
70+
if let Some(catch_unwind) = catch_unwind {
71+
catch_unwind.visit_machine_values(visit);
72+
}
73+
}
74+
}
75+
6676
/// Extra memory kinds
6777
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6878
pub enum MiriMemoryKind {
@@ -593,12 +603,36 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
593603

594604
impl VisitMachineValues for MiriMachine<'_, '_> {
595605
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
596-
// FIXME: visit the missing fields: env vars, weak mem, the MemPlace fields in the machine,
597-
// DirHandler, extern_statics, the Stacked Borrows base pointers; maybe more.
598-
let MiriMachine { threads, tls, .. } = self;
606+
let MiriMachine {
607+
threads,
608+
tls,
609+
env_vars,
610+
argc,
611+
argv,
612+
cmd_line,
613+
extern_statics,
614+
dir_handler,
615+
..
616+
} = self;
599617

600618
threads.visit_machine_values(visit);
601619
tls.visit_machine_values(visit);
620+
env_vars.visit_machine_values(visit);
621+
dir_handler.visit_machine_values(visit);
622+
623+
if let Some(argc) = argc {
624+
visit(&Operand::Indirect(*argc));
625+
}
626+
if let Some(argv) = argv {
627+
visit(&Operand::Indirect(*argv));
628+
}
629+
if let Some(cmd_line) = cmd_line {
630+
visit(&Operand::Indirect(*cmd_line));
631+
}
632+
for ptr in extern_statics.values().copied() {
633+
let ptr: Pointer<Option<Provenance>> = ptr.into();
634+
visit(&Operand::Indirect(MemPlace::from_ptr(ptr)));
635+
}
602636
}
603637
}
604638

src/tools/miri/src/shims/env.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ pub struct EnvVars<'tcx> {
3636
pub(crate) environ: Option<MPlaceTy<'tcx, Provenance>>,
3737
}
3838

39+
impl VisitMachineValues for EnvVars<'_> {
40+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
41+
let EnvVars { map, environ } = self;
42+
43+
for ptr in map.values() {
44+
visit(&Operand::Indirect(MemPlace::from_ptr(*ptr)));
45+
}
46+
47+
if let Some(env) = environ {
48+
visit(&Operand::Indirect(**env));
49+
}
50+
}
51+
}
52+
3953
impl<'tcx> EnvVars<'tcx> {
4054
pub(crate) fn init<'mir>(
4155
ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,

src/tools/miri/src/shims/panic.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ pub struct CatchUnwindData<'tcx> {
3535
ret: mir::BasicBlock,
3636
}
3737

38+
impl VisitMachineValues for CatchUnwindData<'_> {
39+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
40+
visit(&Operand::Indirect(MemPlace::from_ptr(self.catch_fn)));
41+
visit(&Operand::Immediate(Immediate::Scalar(self.data)));
42+
}
43+
}
44+
3845
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
3946
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4047
/// Handles the special `miri_start_panic` intrinsic, which is called

src/tools/miri/src/shims/unix/fs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,14 @@ impl Default for DirHandler {
462462
}
463463
}
464464

465+
impl VisitMachineValues for DirHandler {
466+
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
467+
for dir in self.streams.values() {
468+
visit(&Operand::Indirect(MemPlace::from_ptr(dir.entry)));
469+
}
470+
}
471+
}
472+
465473
fn maybe_sync_file(
466474
file: &File,
467475
writable: bool,

src/tools/miri/src/stacked_borrows/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub struct Stacks {
7979
/// Stores past operations on this allocation
8080
history: AllocHistory,
8181
/// The set of tags that have been exposed inside this allocation.
82-
exposed_tags: FxHashSet<SbTag>,
82+
pub exposed_tags: FxHashSet<SbTag>,
8383
/// Whether this memory has been modified since the last time the tag GC ran
8484
modified_since_last_gc: bool,
8585
}

src/tools/miri/src/stacked_borrows/stack.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ impl Stack {
4343
pub fn retain(&mut self, tags: &FxHashSet<SbTag>) {
4444
let mut first_removed = None;
4545

46-
let mut read_idx = 1;
47-
let mut write_idx = 1;
46+
// For stacks with a known bottom, we never consider removing the bottom-most tag, because
47+
// that is the base tag which exists whether or not there are any pointers to the
48+
// allocation.
49+
let mut read_idx = usize::from(self.unknown_bottom.is_none());
50+
let mut write_idx = read_idx;
4851
while read_idx < self.borrows.len() {
4952
let left = self.borrows[read_idx - 1];
5053
let this = self.borrows[read_idx];

src/tools/miri/src/tag_gc.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
7171
tags.insert(*sb);
7272
}
7373
}
74+
let stacks = alloc
75+
.extra
76+
.stacked_borrows
77+
.as_ref()
78+
.expect("we should not even enter the GC if Stacked Borrows is disabled");
79+
tags.extend(&stacks.borrow().exposed_tags);
80+
81+
if let Some(store_buffers) = alloc.extra.weak_memory.as_ref() {
82+
store_buffers.iter(|val| {
83+
if let Scalar::Ptr(ptr, _) = val {
84+
if let Provenance::Concrete { sb, .. } = ptr.provenance {
85+
tags.insert(sb);
86+
}
87+
}
88+
});
89+
}
7490
},
7591
);
7692

0 commit comments

Comments
 (0)