Skip to content

Commit 3ac7ca4

Browse files
committed
Auto merge of #2075 - y86-dev:master, r=RalfJung
Allow to track multiple alloc-ids, call-ids and pointer tags Closes #2073.
2 parents 2e419e4 + b472ef5 commit 3ac7ca4

File tree

5 files changed

+87
-63
lines changed

5 files changed

+87
-63
lines changed

README.md

+9-5
Original file line numberDiff line numberDiff line change
@@ -314,16 +314,20 @@ environment variable:
314314
ensure alignment. (The standard library `align_to` method works fine in both
315315
modes; under symbolic alignment it only fills the middle slice when the
316316
allocation guarantees sufficient alignment.)
317-
* `-Zmiri-track-alloc-id=<id>` shows a backtrace when the given allocation is
317+
* `-Zmiri-track-alloc-id=<id1>,<id2>,...` shows a backtrace when the given allocations are
318318
being allocated or freed. This helps in debugging memory leaks and
319-
use after free bugs.
320-
* `-Zmiri-track-call-id=<id>` shows a backtrace when the given call id is
319+
use after free bugs. Specifying this argument multiple times does not overwrite the previous
320+
values, instead it appends its values to the list. Listing an id multiple times has no effect.
321+
* `-Zmiri-track-call-id=<id1>,<id2>,...` shows a backtrace when the given call ids are
321322
assigned to a stack frame. This helps in debugging UB related to Stacked
322-
Borrows "protectors".
323-
* `-Zmiri-track-pointer-tag=<tag>` shows a backtrace when the given pointer tag
323+
Borrows "protectors". Specifying this argument multiple times does not overwrite the previous
324+
values, instead it appends its values to the list. Listing an id multiple times has no effect.
325+
* `-Zmiri-track-pointer-tag=<tag1>,<tag2>,...` shows a backtrace when a given pointer tag
324326
is popped from a borrow stack (which is where the tag becomes invalid and any
325327
future use of it will error). This helps you in finding out why UB is
326328
happening and where in your code would be a good place to look for it.
329+
Specifying this argument multiple times does not overwrite the previous
330+
values, instead it appends its values to the list. Listing a tag multiple times has no effect.
327331
* `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can
328332
make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent
329333
aliasing issues in code that Miri accepts by default. You can recognize false positives by

src/bin/miri.rs

+47-31
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,13 @@ fn run_compiler(
251251
std::process::exit(exit_code)
252252
}
253253

254+
/// Parses a comma separated list of `T` from the given string:
255+
///
256+
/// `<value1>,<value2>,<value3>,...`
257+
fn parse_comma_list<T: FromStr>(input: &str) -> Result<Vec<T>, T::Err> {
258+
input.split(',').map(str::parse::<T>).collect()
259+
}
260+
254261
fn main() {
255262
rustc_driver::install_ice_hook();
256263

@@ -397,46 +404,55 @@ fn main() {
397404
.push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned());
398405
}
399406
arg if arg.starts_with("-Zmiri-track-pointer-tag=") => {
400-
let id: u64 =
401-
match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() {
402-
Ok(id) => id,
403-
Err(err) =>
404-
panic!(
405-
"-Zmiri-track-pointer-tag requires a valid `u64` argument: {}",
406-
err
407-
),
408-
};
409-
if let Some(id) = miri::PtrId::new(id) {
410-
miri_config.tracked_pointer_tag = Some(id);
411-
} else {
412-
panic!("-Zmiri-track-pointer-tag requires a nonzero argument");
407+
let ids: Vec<u64> = match parse_comma_list(
408+
arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap(),
409+
) {
410+
Ok(ids) => ids,
411+
Err(err) =>
412+
panic!(
413+
"-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}",
414+
err
415+
),
416+
};
417+
for id in ids.into_iter().map(miri::PtrId::new) {
418+
if let Some(id) = id {
419+
miri_config.tracked_pointer_tags.insert(id);
420+
} else {
421+
panic!("-Zmiri-track-pointer-tag requires nonzero arguments");
422+
}
413423
}
414424
}
415425
arg if arg.starts_with("-Zmiri-track-call-id=") => {
416-
let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() {
417-
Ok(id) => id,
426+
let ids: Vec<u64> = match parse_comma_list(
427+
arg.strip_prefix("-Zmiri-track-call-id=").unwrap(),
428+
) {
429+
Ok(ids) => ids,
418430
Err(err) =>
419-
panic!("-Zmiri-track-call-id requires a valid `u64` argument: {}", err),
431+
panic!(
432+
"-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}",
433+
err
434+
),
420435
};
421-
if let Some(id) = miri::CallId::new(id) {
422-
miri_config.tracked_call_id = Some(id);
423-
} else {
424-
panic!("-Zmiri-track-call-id requires a nonzero argument");
436+
for id in ids.into_iter().map(miri::CallId::new) {
437+
if let Some(id) = id {
438+
miri_config.tracked_call_ids.insert(id);
439+
} else {
440+
panic!("-Zmiri-track-call-id requires a nonzero argument");
441+
}
425442
}
426443
}
427444
arg if arg.starts_with("-Zmiri-track-alloc-id=") => {
428-
let id = match arg
429-
.strip_prefix("-Zmiri-track-alloc-id=")
430-
.unwrap()
431-
.parse()
432-
.ok()
433-
.and_then(NonZeroU64::new)
434-
{
435-
Some(id) => id,
436-
None =>
437-
panic!("-Zmiri-track-alloc-id requires a valid non-zero `u64` argument"),
445+
let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZeroU64>(
446+
arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap(),
447+
) {
448+
Ok(ids) => ids.into_iter().map(miri::AllocId).collect(),
449+
Err(err) =>
450+
panic!(
451+
"-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}",
452+
err
453+
),
438454
};
439-
miri_config.tracked_alloc_id = Some(miri::AllocId(id));
455+
miri_config.tracked_alloc_ids.extend(ids);
440456
}
441457
arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => {
442458
let rate = match arg

src/eval.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use rustc_target::spec::abi::Abi;
1515

1616
use rustc_session::config::EntryFnType;
1717

18+
use std::collections::HashSet;
19+
1820
use crate::*;
1921

2022
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -91,12 +93,12 @@ pub struct MiriConfig {
9193
pub args: Vec<String>,
9294
/// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
9395
pub seed: Option<u64>,
94-
/// The stacked borrows pointer id to report about
95-
pub tracked_pointer_tag: Option<PtrId>,
96-
/// The stacked borrows call ID to report about
97-
pub tracked_call_id: Option<CallId>,
98-
/// The allocation id to report about.
99-
pub tracked_alloc_id: Option<AllocId>,
96+
/// The stacked borrows pointer ids to report about
97+
pub tracked_pointer_tags: HashSet<PtrId>,
98+
/// The stacked borrows call IDs to report about
99+
pub tracked_call_ids: HashSet<CallId>,
100+
/// The allocation ids to report about.
101+
pub tracked_alloc_ids: HashSet<AllocId>,
100102
/// Whether to track raw pointers in stacked borrows.
101103
pub tag_raw: bool,
102104
/// Determine if data race detection should be enabled
@@ -130,9 +132,9 @@ impl Default for MiriConfig {
130132
forwarded_env_vars: vec![],
131133
args: vec![],
132134
seed: None,
133-
tracked_pointer_tag: None,
134-
tracked_call_id: None,
135-
tracked_alloc_id: None,
135+
tracked_pointer_tags: HashSet::default(),
136+
tracked_call_ids: HashSet::default(),
137+
tracked_alloc_ids: HashSet::default(),
136138
tag_raw: false,
137139
data_race_detector: true,
138140
cmpxchg_weak_failure_rate: 0.8,

src/machine.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use std::borrow::Cow;
55
use std::cell::RefCell;
6+
use std::collections::HashSet;
67
use std::fmt;
78
use std::num::NonZeroU64;
89
use std::time::Instant;
@@ -281,9 +282,9 @@ pub struct Evaluator<'mir, 'tcx> {
281282
/// Needs to be queried by ptr_to_int, hence needs interior mutability.
282283
pub(crate) rng: RefCell<StdRng>,
283284

284-
/// An allocation ID to report when it is being allocated
285+
/// The allocation IDs to report when they are being allocated
285286
/// (helps for debugging memory leaks and use after free bugs).
286-
tracked_alloc_id: Option<AllocId>,
287+
tracked_alloc_ids: HashSet<AllocId>,
287288

288289
/// Controls whether alignment of memory accesses is being checked.
289290
pub(crate) check_alignment: AlignmentCheck,
@@ -303,8 +304,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
303304
let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
304305
let stacked_borrows = if config.stacked_borrows {
305306
Some(RefCell::new(stacked_borrows::GlobalStateInner::new(
306-
config.tracked_pointer_tag,
307-
config.tracked_call_id,
307+
config.tracked_pointer_tags.clone(),
308+
config.tracked_call_ids.clone(),
308309
config.tag_raw,
309310
)))
310311
} else {
@@ -340,7 +341,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
340341
local_crates,
341342
extern_statics: FxHashMap::default(),
342343
rng: RefCell::new(rng),
343-
tracked_alloc_id: config.tracked_alloc_id,
344+
tracked_alloc_ids: config.tracked_alloc_ids.clone(),
344345
check_alignment: config.check_alignment,
345346
cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
346347
}
@@ -560,7 +561,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
560561
alloc: Cow<'b, Allocation>,
561562
kind: Option<MemoryKind<Self::MemoryKind>>,
562563
) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>> {
563-
if Some(id) == ecx.machine.tracked_alloc_id {
564+
if ecx.machine.tracked_alloc_ids.contains(&id) {
564565
register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id));
565566
}
566567

@@ -669,7 +670,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
669670
(alloc_id, tag): (AllocId, Self::TagExtra),
670671
range: AllocRange,
671672
) -> InterpResult<'tcx> {
672-
if Some(alloc_id) == machine.tracked_alloc_id {
673+
if machine.tracked_alloc_ids.contains(&alloc_id) {
673674
register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
674675
}
675676
if let Some(data_race) = &mut alloc_extra.data_race {

src/stacked_borrows.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_middle::ty::{
1515
};
1616
use rustc_span::DUMMY_SP;
1717
use rustc_target::abi::Size;
18+
use std::collections::HashSet;
1819

1920
use crate::*;
2021

@@ -104,10 +105,10 @@ pub struct GlobalStateInner {
104105
next_call_id: CallId,
105106
/// Those call IDs corresponding to functions that are still running.
106107
active_calls: FxHashSet<CallId>,
107-
/// The pointer id to trace
108-
tracked_pointer_tag: Option<PtrId>,
109-
/// The call id to trace
110-
tracked_call_id: Option<CallId>,
108+
/// The pointer ids to trace
109+
tracked_pointer_tags: HashSet<PtrId>,
110+
/// The call ids to trace
111+
tracked_call_ids: HashSet<CallId>,
111112
/// Whether to track raw pointers.
112113
tag_raw: bool,
113114
}
@@ -158,24 +159,24 @@ impl fmt::Display for RefKind {
158159
/// Utilities for initialization and ID generation
159160
impl GlobalStateInner {
160161
pub fn new(
161-
tracked_pointer_tag: Option<PtrId>,
162-
tracked_call_id: Option<CallId>,
162+
tracked_pointer_tags: HashSet<PtrId>,
163+
tracked_call_ids: HashSet<CallId>,
163164
tag_raw: bool,
164165
) -> Self {
165166
GlobalStateInner {
166167
next_ptr_id: NonZeroU64::new(1).unwrap(),
167168
base_ptr_ids: FxHashMap::default(),
168169
next_call_id: NonZeroU64::new(1).unwrap(),
169170
active_calls: FxHashSet::default(),
170-
tracked_pointer_tag,
171-
tracked_call_id,
171+
tracked_pointer_tags,
172+
tracked_call_ids,
172173
tag_raw,
173174
}
174175
}
175176

176177
fn new_ptr(&mut self) -> PtrId {
177178
let id = self.next_ptr_id;
178-
if Some(id) == self.tracked_pointer_tag {
179+
if self.tracked_pointer_tags.contains(&id) {
179180
register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id));
180181
}
181182
self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap();
@@ -185,7 +186,7 @@ impl GlobalStateInner {
185186
pub fn new_call(&mut self) -> CallId {
186187
let id = self.next_call_id;
187188
trace!("new_call: Assigning ID {}", id);
188-
if Some(id) == self.tracked_call_id {
189+
if self.tracked_call_ids.contains(&id) {
189190
register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id));
190191
}
191192
assert!(self.active_calls.insert(id));
@@ -311,7 +312,7 @@ impl<'tcx> Stack {
311312
global: &GlobalStateInner,
312313
) -> InterpResult<'tcx> {
313314
if let SbTag::Tagged(id) = item.tag {
314-
if Some(id) == global.tracked_pointer_tag {
315+
if global.tracked_pointer_tags.contains(&id) {
315316
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(
316317
item.clone(),
317318
provoking_access,

0 commit comments

Comments
 (0)