Skip to content

Commit

Permalink
Auto merge of #1080 - rust-lang:stacked_borrow_tracing, r=RalfJung
Browse files Browse the repository at this point in the history
Add a scheme to find the place where an id was destroyed

cc #974

I'm not too happy with it, but since stacked borrows don't have access to the current call stack, I can't just report a warning as per #797

We could add some global mutex that we can throw strings at and `step` will clear out that mutex and report warnings before moving the `statement_id` or the `block_id`, not sure how well that would work. For now I think this is sufficient
  • Loading branch information
bors committed Dec 10, 2019
2 parents 4ebc030 + 8d409a7 commit f94bc71
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 11 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Several `-Z` flags are relevant for Miri:
the program has access to host resources such as environment variables and
randomness (and, eventually, file systems and more).
* `-Zmiri-ignore-leaks` disables the memory leak checker.
* `-Zmiri-env-exclude=<var>` keeps the `var` environment variable isolated from
* `-Zmiri-env-exclude=<var>` keeps the `var` environment variable isolated from
the host. Can be used multiple times to exclude several variables. The `TERM`
environment variable is excluded by default.
* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri
Expand All @@ -171,6 +171,11 @@ Several `-Z` flags are relevant for Miri:
sets this flag per default.
* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri
enables this per default because it is needed for validation.
* `-Zmiri-track-pointer-tag=<tag>` aborts interpretation with a backtrace when the
given pointer tag is popped from a borrow stack (which is where the tag
becomes invalid and any future use of it will error anyway). This helps you
in finding out why UB is happening and where in your code would be a good
place to look for it.

Moreover, Miri recognizes some environment variables:

Expand Down
1 change: 1 addition & 0 deletions benches/helpers/miri_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> {
excluded_env_vars: vec![],
args: vec![],
seed: None,
tracked_pointer_tag: None,
};
eval_main(tcx, entry_def_id, config);
});
Expand Down
4 changes: 3 additions & 1 deletion src/bin/miri-rustc-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
excluded_env_vars: vec![],
args: vec![],
seed: None,
tracked_pointer_tag: None,
};
let did = self.0.hir().body_owner_def_id(body_id);
println!("running test: {}", self.0.def_path_debug_str(did));
Expand All @@ -64,7 +65,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
ignore_leaks: false,
excluded_env_vars: vec![],
args: vec![],
seed: None
seed: None,
tracked_pointer_tag: None,
};
miri::eval_main(tcx, entry_def_id, config);

Expand Down
13 changes: 13 additions & 0 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ fn main() {
let mut communicate = false;
let mut ignore_leaks = false;
let mut seed: Option<u64> = None;
let mut tracked_pointer_tag: Option<miri::PtrId> = None;
let mut rustc_args = vec![];
let mut miri_args = vec![];
let mut after_dashdash = false;
Expand Down Expand Up @@ -176,6 +177,17 @@ fn main() {
arg if arg.starts_with("-Zmiri-env-exclude=") => {
excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned());
},
arg if arg.starts_with("-Zmiri-track-pointer-tag=") => {
let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() {
Ok(id) => id,
Err(err) => panic!("-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", err),
};
if let Some(id) = miri::PtrId::new(id) {
tracked_pointer_tag = Some(id);
} else {
panic!("-Zmiri-track-pointer-tag must be a nonzero id");
}
},
_ => {
rustc_args.push(arg);
}
Expand Down Expand Up @@ -208,6 +220,7 @@ fn main() {
excluded_env_vars,
seed,
args: miri_args,
tracked_pointer_tag,
};
rustc_driver::install_ice_hook();
let result = rustc_driver::catch_fatal_errors(move || {
Expand Down
7 changes: 6 additions & 1 deletion src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ 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 borrow id to report about
pub tracked_pointer_tag: Option<PtrId>,
}

/// Details of premature program termination.
pub enum TerminationInfo {
Exit(i64),
PoppedTrackedPointerTag(Item),
Abort,
}

Expand All @@ -47,7 +50,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
tcx.at(syntax::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
Evaluator::new(config.communicate),
MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_pointer_tag),
);
// Complete initialization.
EnvVars::init(&mut ecx, config.excluded_env_vars);
Expand Down Expand Up @@ -216,6 +219,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
.expect("invalid MachineStop payload");
match info {
TerminationInfo::Exit(code) => return Some(*code),
TerminationInfo::PoppedTrackedPointerTag(item) =>
format!("popped tracked tag for item {:?}", item),
TerminationInfo::Abort =>
format!("the evaluated program aborted execution")
}
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
pub use crate::range_map::RangeMap;
pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt};
pub use crate::mono_hash_map::MonoHashMap;
pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item};
pub use crate::stacked_borrows::{
EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item, PtrId,
GlobalState,
};
pub use crate::machine::{
PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS,
MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt,
Expand Down
4 changes: 2 additions & 2 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ pub struct MemoryExtra {
}

impl MemoryExtra {
pub fn new(rng: StdRng, validate: bool) -> Self {
pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option<PtrId>) -> Self {
MemoryExtra {
stacked_borrows: Default::default(),
stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))),
intptrcast: Default::default(),
rng: RefCell::new(rng),
validate,
Expand Down
16 changes: 11 additions & 5 deletions src/stacked_borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc::hir::Mutability::{Mutable, Immutable};
use rustc::mir::RetagKind;

use crate::{
InterpResult, HelpersEvalContextExt,
InterpResult, HelpersEvalContextExt, TerminationInfo,
MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy,
};

Expand Down Expand Up @@ -105,6 +105,8 @@ pub struct GlobalState {
next_call_id: CallId,
/// Those call IDs corresponding to functions that are still running.
active_calls: HashSet<CallId>,
/// The id to trace in this execution run
tracked_pointer_tag: Option<PtrId>,
}
/// Memory extra state gives us interior mutable access to the global state.
pub type MemoryExtra = Rc<RefCell<GlobalState>>;
Expand Down Expand Up @@ -151,18 +153,17 @@ impl fmt::Display for RefKind {
}

/// Utilities for initialization and ID generation
impl Default for GlobalState {
fn default() -> Self {
impl GlobalState {
pub fn new(tracked_pointer_tag: Option<PtrId>) -> Self {
GlobalState {
next_ptr_id: NonZeroU64::new(1).unwrap(),
base_ptr_ids: HashMap::default(),
next_call_id: NonZeroU64::new(1).unwrap(),
active_calls: HashSet::default(),
tracked_pointer_tag,
}
}
}

impl GlobalState {
fn new_ptr(&mut self) -> PtrId {
let id = self.next_ptr_id;
self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap();
Expand Down Expand Up @@ -270,6 +271,11 @@ impl<'tcx> Stack {

/// Check if the given item is protected.
fn check_protector(item: &Item, tag: Option<Tag>, global: &GlobalState) -> InterpResult<'tcx> {
if let Tag::Tagged(id) = item.tag {
if Some(id) == global.tracked_pointer_tag {
throw_machine_stop!(TerminationInfo::PoppedTrackedPointerTag(item.clone()));
}
}
if let Some(call) = item.protector {
if global.is_active(call) {
if let Some(tag) = tag {
Expand Down

0 comments on commit f94bc71

Please sign in to comment.