Skip to content

Commit e7ef64f

Browse files
committed
Auto merge of #1463 - RalfJung:track-call-id, r=oli-obk
add option to track call IDs
2 parents b4ccb07 + c379793 commit e7ef64f

File tree

7 files changed

+46
-15
lines changed

7 files changed

+46
-15
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ Miri adds its own set of `-Z` flags:
196196
is popped from a borrow stack (which is where the tag becomes invalid and any
197197
future use of it will error). This helps you in finding out why UB is
198198
happening and where in your code would be a good place to look for it.
199+
* `-Zmiri-track-call-id=<id>` shows a backtrace when the given call id is
200+
assigned to a stack frame. This helps in debugging UB related to Stacked
201+
Borrows "protectors".
199202

200203
[alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074
201204

src/bin/miri.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ fn main() {
172172
let mut ignore_leaks = false;
173173
let mut seed: Option<u64> = None;
174174
let mut tracked_pointer_tag: Option<miri::PtrId> = None;
175+
let mut tracked_call_id: Option<miri::CallId> = None;
175176
let mut tracked_alloc_id: Option<miri::AllocId> = None;
176177
let mut rustc_args = vec![];
177178
let mut crate_args = vec![];
@@ -233,26 +234,38 @@ fn main() {
233234
.push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned());
234235
}
235236
arg if arg.starts_with("-Zmiri-track-pointer-tag=") => {
236-
let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse()
237-
{
237+
let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() {
238238
Ok(id) => id,
239239
Err(err) => panic!(
240-
"-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}",
240+
"-Zmiri-track-pointer-tag requires a valid `u64` argument: {}",
241241
err
242242
),
243243
};
244244
if let Some(id) = miri::PtrId::new(id) {
245245
tracked_pointer_tag = Some(id);
246246
} else {
247-
panic!("-Zmiri-track-pointer-tag must be a nonzero id");
247+
panic!("-Zmiri-track-pointer-tag requires a nonzero argument");
248+
}
249+
}
250+
arg if arg.starts_with("-Zmiri-track-call-id=") => {
251+
let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() {
252+
Ok(id) => id,
253+
Err(err) => panic!(
254+
"-Zmiri-track-call-id requires a valid `u64` argument: {}",
255+
err
256+
),
257+
};
258+
if let Some(id) = miri::CallId::new(id) {
259+
tracked_call_id = Some(id);
260+
} else {
261+
panic!("-Zmiri-track-call-id requires a nonzero argument");
248262
}
249263
}
250264
arg if arg.starts_with("-Zmiri-track-alloc-id=") => {
251-
let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse()
252-
{
265+
let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() {
253266
Ok(id) => id,
254267
Err(err) => panic!(
255-
"-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}",
268+
"-Zmiri-track-alloc-id requires a valid `u64` argument: {}",
256269
err
257270
),
258271
};
@@ -278,6 +291,7 @@ fn main() {
278291
seed,
279292
args: crate_args,
280293
tracked_pointer_tag,
294+
tracked_call_id,
281295
tracked_alloc_id,
282296
};
283297
run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config })

src/diagnostics.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ impl MachineStopType for TerminationInfo {}
4040

4141
/// Miri specific diagnostics
4242
pub enum NonHaltingDiagnostic {
43-
PoppedTrackedPointerTag(Item),
43+
PoppedPointerTag(Item),
44+
CreatedCallId(CallId),
4445
CreatedAlloc(AllocId),
4546
FreedAlloc(AllocId),
4647
}
@@ -204,8 +205,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
204205
for e in diagnostics.borrow_mut().drain(..) {
205206
use NonHaltingDiagnostic::*;
206207
let msg = match e {
207-
PoppedTrackedPointerTag(item) =>
208+
PoppedPointerTag(item) =>
208209
format!("popped tracked tag for item {:?}", item),
210+
CreatedCallId(id) =>
211+
format!("function call with id {}", id),
209212
CreatedAlloc(AllocId(id)) =>
210213
format!("created allocation with id {}", id),
211214
FreedAlloc(AllocId(id)) =>

src/eval.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ pub struct MiriConfig {
3131
pub args: Vec<String>,
3232
/// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
3333
pub seed: Option<u64>,
34-
/// The stacked borrow id to report about
34+
/// The stacked borrows pointer id to report about
3535
pub tracked_pointer_tag: Option<PtrId>,
36+
/// The stacked borrows call ID to report about
37+
pub tracked_call_id: Option<CallId>,
3638
/// The allocation id to report about.
3739
pub tracked_alloc_id: Option<AllocId>,
3840
}
@@ -49,6 +51,7 @@ impl Default for MiriConfig {
4951
args: vec![],
5052
seed: None,
5153
tracked_pointer_tag: None,
54+
tracked_call_id: None,
5255
tracked_alloc_id: None,
5356
}
5457
}
@@ -74,6 +77,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
7477
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
7578
config.stacked_borrows,
7679
config.tracked_pointer_tag,
80+
config.tracked_call_id,
7781
config.tracked_alloc_id,
7882
config.check_alignment,
7983
),

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub use crate::mono_hash_map::MonoHashMap;
6565
pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
6666
pub use crate::range_map::RangeMap;
6767
pub use crate::stacked_borrows::{
68-
EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag,
68+
EvalContextExt as StackedBorEvalContextExt, Item, Permission, CallId, PtrId, Stack, Stacks, Tag,
6969
};
7070
pub use crate::thread::{
7171
EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState,

src/machine.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,12 @@ impl MemoryExtra {
129129
rng: StdRng,
130130
stacked_borrows: bool,
131131
tracked_pointer_tag: Option<PtrId>,
132+
tracked_call_id: Option<CallId>,
132133
tracked_alloc_id: Option<AllocId>,
133134
check_alignment: bool,
134135
) -> Self {
135136
let stacked_borrows = if stacked_borrows {
136-
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag))))
137+
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id))))
137138
} else {
138139
None
139140
};

src/stacked_borrows.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,10 @@ pub struct GlobalState {
104104
next_call_id: CallId,
105105
/// Those call IDs corresponding to functions that are still running.
106106
active_calls: FxHashSet<CallId>,
107-
/// The id to trace in this execution run
107+
/// The pointer id to trace
108108
tracked_pointer_tag: Option<PtrId>,
109+
/// The call id to trace
110+
tracked_call_id: Option<CallId>,
109111
}
110112
/// Memory extra state gives us interior mutable access to the global state.
111113
pub type MemoryExtra = Rc<RefCell<GlobalState>>;
@@ -153,13 +155,14 @@ impl fmt::Display for RefKind {
153155

154156
/// Utilities for initialization and ID generation
155157
impl GlobalState {
156-
pub fn new(tracked_pointer_tag: Option<PtrId>) -> Self {
158+
pub fn new(tracked_pointer_tag: Option<PtrId>, tracked_call_id: Option<CallId>) -> Self {
157159
GlobalState {
158160
next_ptr_id: NonZeroU64::new(1).unwrap(),
159161
base_ptr_ids: FxHashMap::default(),
160162
next_call_id: NonZeroU64::new(1).unwrap(),
161163
active_calls: FxHashSet::default(),
162164
tracked_pointer_tag,
165+
tracked_call_id,
163166
}
164167
}
165168

@@ -172,6 +175,9 @@ impl GlobalState {
172175
pub fn new_call(&mut self) -> CallId {
173176
let id = self.next_call_id;
174177
trace!("new_call: Assigning ID {}", id);
178+
if Some(id) == self.tracked_call_id {
179+
register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id));
180+
}
175181
assert!(self.active_calls.insert(id));
176182
self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap();
177183
id
@@ -277,7 +283,7 @@ impl<'tcx> Stack {
277283
fn check_protector(item: &Item, tag: Option<Tag>, global: &GlobalState) -> InterpResult<'tcx> {
278284
if let Tag::Tagged(id) = item.tag {
279285
if Some(id) == global.tracked_pointer_tag {
280-
register_diagnostic(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone()));
286+
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone()));
281287
}
282288
}
283289
if let Some(call) = item.protector {

0 commit comments

Comments
 (0)