Added support for multiple tracked pointers, allocs and calls

- Changed arg parsing to handle comma seperated list of `u64`'s.
- Changed type and field names of config, executor and global state
  to hold a set of tracked ids.
- Adjusted Readme:
    - explained list format
    - arguments do not overwrite, instead append
    - no effect on duplication
- Created a parsing function for comma separated lists
- Added error printing to alloc_id parsing
This commit is contained in:
y86-dev 2022-04-20 11:10:59 +02:00
parent c9039de613
commit bf17dbebc9
5 changed files with 87 additions and 63 deletions

View file

@ -251,6 +251,13 @@ fn run_compiler(
std::process::exit(exit_code)
}
/// Parses a comma separated list of `T` from the given string:
///
/// `<value1>,<value2>,<value3>,...`
fn parse_comma_list<T: FromStr>(input: &str) -> Result<Vec<T>, T::Err> {
input.split(',').map(str::parse::<T>).collect()
}
fn main() {
rustc_driver::install_ice_hook();
@ -397,46 +404,55 @@ fn main() {
.push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned());
}
arg if arg.starts_with("-Zmiri-track-pointer-tag=") => {
let id: u64 =
match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() {
Ok(id) => id,
Err(err) =>
panic!(
"-Zmiri-track-pointer-tag requires a valid `u64` argument: {}",
err
),
};
if let Some(id) = miri::PtrId::new(id) {
miri_config.tracked_pointer_tag = Some(id);
} else {
panic!("-Zmiri-track-pointer-tag requires a nonzero argument");
let ids: Vec<u64> = match parse_comma_list(
arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap(),
) {
Ok(ids) => ids,
Err(err) =>
panic!(
"-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}",
err
),
};
for id in ids.into_iter().map(miri::PtrId::new) {
if let Some(id) = id {
miri_config.tracked_pointer_tags.insert(id);
} else {
panic!("-Zmiri-track-pointer-tag requires nonzero arguments");
}
}
}
arg if arg.starts_with("-Zmiri-track-call-id=") => {
let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() {
Ok(id) => id,
let ids: Vec<u64> = match parse_comma_list(
arg.strip_prefix("-Zmiri-track-call-id=").unwrap(),
) {
Ok(ids) => ids,
Err(err) =>
panic!("-Zmiri-track-call-id requires a valid `u64` argument: {}", err),
panic!(
"-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}",
err
),
};
if let Some(id) = miri::CallId::new(id) {
miri_config.tracked_call_id = Some(id);
} else {
panic!("-Zmiri-track-call-id requires a nonzero argument");
for id in ids.into_iter().map(miri::CallId::new) {
if let Some(id) = id {
miri_config.tracked_call_ids.insert(id);
} else {
panic!("-Zmiri-track-call-id requires a nonzero argument");
}
}
}
arg if arg.starts_with("-Zmiri-track-alloc-id=") => {
let id = match arg
.strip_prefix("-Zmiri-track-alloc-id=")
.unwrap()
.parse()
.ok()
.and_then(NonZeroU64::new)
{
Some(id) => id,
None =>
panic!("-Zmiri-track-alloc-id requires a valid non-zero `u64` argument"),
let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZeroU64>(
arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap(),
) {
Ok(ids) => ids.into_iter().map(miri::AllocId).collect(),
Err(err) =>
panic!(
"-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}",
err
),
};
miri_config.tracked_alloc_id = Some(miri::AllocId(id));
miri_config.tracked_alloc_ids.extend(ids);
}
arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => {
let rate = match arg

View file

@ -15,6 +15,8 @@ use rustc_target::spec::abi::Abi;
use rustc_session::config::EntryFnType;
use std::collections::HashSet;
use crate::*;
#[derive(Copy, Clone, Debug, PartialEq)]
@ -91,12 +93,12 @@ pub struct MiriConfig {
pub args: Vec<String>,
/// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
pub seed: Option<u64>,
/// The stacked borrows pointer id to report about
pub tracked_pointer_tag: Option<PtrId>,
/// The stacked borrows call ID to report about
pub tracked_call_id: Option<CallId>,
/// The allocation id to report about.
pub tracked_alloc_id: Option<AllocId>,
/// The stacked borrows pointer ids to report about
pub tracked_pointer_tags: HashSet<PtrId>,
/// The stacked borrows call IDs to report about
pub tracked_call_ids: HashSet<CallId>,
/// The allocation ids to report about.
pub tracked_alloc_ids: HashSet<AllocId>,
/// Whether to track raw pointers in stacked borrows.
pub tag_raw: bool,
/// Determine if data race detection should be enabled
@ -130,9 +132,9 @@ impl Default for MiriConfig {
forwarded_env_vars: vec![],
args: vec![],
seed: None,
tracked_pointer_tag: None,
tracked_call_id: None,
tracked_alloc_id: None,
tracked_pointer_tags: Default::default(),
tracked_call_ids: Default::default(),
tracked_alloc_ids: Default::default(),
tag_raw: false,
data_race_detector: true,
cmpxchg_weak_failure_rate: 0.8,

View file

@ -3,6 +3,7 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use std::fmt;
use std::num::NonZeroU64;
use std::time::Instant;
@ -281,9 +282,9 @@ pub struct Evaluator<'mir, 'tcx> {
/// Needs to be queried by ptr_to_int, hence needs interior mutability.
pub(crate) rng: RefCell<StdRng>,
/// An allocation ID to report when it is being allocated
/// The allocation IDs to report when they are being allocated
/// (helps for debugging memory leaks and use after free bugs).
tracked_alloc_id: Option<AllocId>,
tracked_alloc_ids: HashSet<AllocId>,
/// Controls whether alignment of memory accesses is being checked.
pub(crate) check_alignment: AlignmentCheck,
@ -303,8 +304,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
let stacked_borrows = if config.stacked_borrows {
Some(RefCell::new(stacked_borrows::GlobalStateInner::new(
config.tracked_pointer_tag,
config.tracked_call_id,
config.tracked_pointer_tags.clone(),
config.tracked_call_ids.clone(),
config.tag_raw,
)))
} else {
@ -340,7 +341,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
local_crates,
extern_statics: FxHashMap::default(),
rng: RefCell::new(rng),
tracked_alloc_id: config.tracked_alloc_id,
tracked_alloc_ids: config.tracked_alloc_ids.clone(),
check_alignment: config.check_alignment,
cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
}
@ -560,7 +561,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
alloc: Cow<'b, Allocation>,
kind: Option<MemoryKind<Self::MemoryKind>>,
) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>> {
if Some(id) == ecx.machine.tracked_alloc_id {
if ecx.machine.tracked_alloc_ids.contains(&id) {
register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id));
}
@ -669,7 +670,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
(alloc_id, tag): (AllocId, Self::TagExtra),
range: AllocRange,
) -> InterpResult<'tcx> {
if Some(alloc_id) == machine.tracked_alloc_id {
if machine.tracked_alloc_ids.contains(&alloc_id) {
register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
}
if let Some(data_race) = &mut alloc_extra.data_race {

View file

@ -15,6 +15,7 @@ use rustc_middle::ty::{
};
use rustc_span::DUMMY_SP;
use rustc_target::abi::Size;
use std::collections::HashSet;
use crate::*;
@ -104,10 +105,10 @@ pub struct GlobalStateInner {
next_call_id: CallId,
/// Those call IDs corresponding to functions that are still running.
active_calls: FxHashSet<CallId>,
/// The pointer id to trace
tracked_pointer_tag: Option<PtrId>,
/// The call id to trace
tracked_call_id: Option<CallId>,
/// The pointer ids to trace
tracked_pointer_tags: HashSet<PtrId>,
/// The call ids to trace
tracked_call_ids: HashSet<CallId>,
/// Whether to track raw pointers.
tag_raw: bool,
}
@ -158,8 +159,8 @@ impl fmt::Display for RefKind {
/// Utilities for initialization and ID generation
impl GlobalStateInner {
pub fn new(
tracked_pointer_tag: Option<PtrId>,
tracked_call_id: Option<CallId>,
tracked_pointer_tags: HashSet<PtrId>,
tracked_call_ids: HashSet<CallId>,
tag_raw: bool,
) -> Self {
GlobalStateInner {
@ -167,15 +168,15 @@ impl GlobalStateInner {
base_ptr_ids: FxHashMap::default(),
next_call_id: NonZeroU64::new(1).unwrap(),
active_calls: FxHashSet::default(),
tracked_pointer_tag,
tracked_call_id,
tracked_pointer_tags,
tracked_call_ids,
tag_raw,
}
}
fn new_ptr(&mut self) -> PtrId {
let id = self.next_ptr_id;
if Some(id) == self.tracked_pointer_tag {
if self.tracked_pointer_tags.contains(&id) {
register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id));
}
self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap();
@ -185,7 +186,7 @@ impl GlobalStateInner {
pub fn new_call(&mut self) -> CallId {
let id = self.next_call_id;
trace!("new_call: Assigning ID {}", id);
if Some(id) == self.tracked_call_id {
if self.tracked_call_ids.contains(&id) {
register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id));
}
assert!(self.active_calls.insert(id));
@ -311,7 +312,7 @@ impl<'tcx> Stack {
global: &GlobalStateInner,
) -> InterpResult<'tcx> {
if let SbTag::Tagged(id) = item.tag {
if Some(id) == global.tracked_pointer_tag {
if global.tracked_pointer_tags.contains(&id) {
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(
item.clone(),
provoking_access,