Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add an option to track raw pointer tags in Stacked Borrows #1603

Merged
merged 5 commits into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,17 @@ environment variable:
* `-Zmiri-track-alloc-id=<id>` shows a backtrace when the given allocation is
being allocated or freed. This helps in debugging memory leaks and
use after free bugs.
* `-Zmiri-track-call-id=<id>` shows a backtrace when the given call id is
assigned to a stack frame. This helps in debugging UB related to Stacked
Borrows "protectors".
* `-Zmiri-track-pointer-tag=<tag>` shows 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). This helps you in finding out why UB is
happening and where in your code would be a good place to look for it.
* `-Zmiri-track-call-id=<id>` shows a backtrace when the given call id is
assigned to a stack frame. This helps in debugging UB related to Stacked
Borrows "protectors".
* `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you construct a test for both the false positive case as well as an example where we now detect latent aliasing where we didn't before? (I'm guessing under certain circumstances they could be one and the same test? we'd just detect the aliasing earlier now)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example with a false positive caused by this flag is run-pass/box.rs, since it casts a ptr to an int and back.

I can add a test for a bug that would otherwise be missed (rust-lang/rust#78477 is the example that motivated this change).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added such a test.

raw pointers. This can make valid code fail to pass the checks (when
integer-pointer casts are involved), but also can help identify latent
aliasing issues in code that Miri accepts by default.

Some native rustc `-Z` flags are also very relevant for Miri:

Expand Down
3 changes: 3 additions & 0 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ fn main() {
"-Zmiri-ignore-leaks" => {
miri_config.ignore_leaks = true;
}
"-Zmiri-track-raw-pointers" => {
miri_config.track_raw = true;
}
"--" => {
after_dashdash = true;
}
Expand Down
14 changes: 4 additions & 10 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
use std::convert::TryFrom;
use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;
use log::info;

use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -48,6 +46,8 @@ pub struct MiriConfig {
pub tracked_call_id: Option<CallId>,
/// The allocation id to report about.
pub tracked_alloc_id: Option<AllocId>,
/// Whether to track raw pointers in stacked borrows.
pub track_raw: bool,
}

impl Default for MiriConfig {
Expand All @@ -64,6 +64,7 @@ impl Default for MiriConfig {
tracked_pointer_tag: None,
tracked_call_id: None,
tracked_alloc_id: None,
track_raw: false,
}
}
}
Expand All @@ -84,14 +85,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
rustc_span::source_map::DUMMY_SP,
param_env,
Evaluator::new(config.communicate, config.validate, layout_cx),
MemoryExtra::new(
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
config.stacked_borrows,
config.tracked_pointer_tag,
config.tracked_call_id,
config.tracked_alloc_id,
config.check_alignment,
),
MemoryExtra::new(&config),
);
// Complete initialization.
EnvVars::init(&mut ecx, config.excluded_env_vars)?;
Expand Down
23 changes: 11 additions & 12 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::fmt;

use log::trace;
use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc_data_structures::fx::FxHashMap;
use rustc_middle::{
Expand Down Expand Up @@ -132,16 +133,14 @@ pub struct MemoryExtra {
}

impl MemoryExtra {
pub fn new(
rng: StdRng,
stacked_borrows: bool,
tracked_pointer_tag: Option<PtrId>,
tracked_call_id: Option<CallId>,
tracked_alloc_id: Option<AllocId>,
check_alignment: AlignmentCheck,
) -> Self {
let stacked_borrows = if stacked_borrows {
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id))))
pub fn new(config: &MiriConfig) -> Self {
let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
let stacked_borrows = if config.stacked_borrows {
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(
config.tracked_pointer_tag,
config.tracked_call_id,
config.track_raw,
))))
} else {
None
};
Expand All @@ -150,8 +149,8 @@ impl MemoryExtra {
intptrcast: Default::default(),
extern_statics: FxHashMap::default(),
rng: RefCell::new(rng),
tracked_alloc_id,
check_alignment,
tracked_alloc_id: config.tracked_alloc_id,
check_alignment: config.check_alignment,
}
}

Expand Down
32 changes: 18 additions & 14 deletions src/stacked_borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ pub struct GlobalState {
tracked_pointer_tag: Option<PtrId>,
/// The call id to trace
tracked_call_id: Option<CallId>,
/// Whether to track raw pointers.
track_raw: bool,
}
/// Memory extra state gives us interior mutable access to the global state.
pub type MemoryExtra = Rc<RefCell<GlobalState>>;
Expand Down Expand Up @@ -155,14 +157,15 @@ impl fmt::Display for RefKind {

/// Utilities for initialization and ID generation
impl GlobalState {
pub fn new(tracked_pointer_tag: Option<PtrId>, tracked_call_id: Option<CallId>) -> Self {
pub fn new(tracked_pointer_tag: Option<PtrId>, tracked_call_id: Option<CallId>, track_raw: bool) -> Self {
GlobalState {
next_ptr_id: NonZeroU64::new(1).unwrap(),
base_ptr_ids: FxHashMap::default(),
next_call_id: NonZeroU64::new(1).unwrap(),
active_calls: FxHashSet::default(),
tracked_pointer_tag,
tracked_call_id,
track_raw,
}
}

Expand Down Expand Up @@ -479,9 +482,12 @@ impl Stacks {
// The base pointer is not unique, so the base permission is `SharedReadWrite`.
MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) =>
(extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite),
// Everything else we handle entirely untagged for now.
// FIXME: experiment with more precise tracking.
_ => (Tag::Untagged, Permission::SharedReadWrite),
// Everything else we handle like raw pointers for now.
_ => {
let mut extra = extra.borrow_mut();
let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged };
(tag, Permission::SharedReadWrite)
}
};
(Stacks::new(size, perm, tag, extra), tag)
}
Expand Down Expand Up @@ -593,16 +599,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}

// Compute new borrow.
let new_tag = match kind {
// Give up tracking for raw pointers.
// FIXME: Experiment with more precise tracking. Blocked on `&raw`
// because `Rc::into_raw` currently creates intermediate references,
// breaking `Rc::from_raw`.
RefKind::Raw { .. } => Tag::Untagged,
// All other pointesr are properly tracked.
_ => Tag::Tagged(
this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr(),
),
let new_tag = {
let mut mem_extra = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut();
match kind {
// Give up tracking for raw pointers.
RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged,
// All other pointers are properly tracked.
_ => Tag::Tagged(mem_extra.new_ptr()),
}
};

// Reborrow.
Expand Down