Skip to content

Commit 274ae04

Browse files
committed
add an option to disable Stacked Borrows
1 parent 36305e3 commit 274ae04

15 files changed

+66
-41
lines changed

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ for example:
1414
* Not sufficiently aligned memory accesses and references
1515
* Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example,
1616
or an invalid enum discriminant)
17-
* **Experimental**: Violations of the rules governing aliasing for reference types
17+
* **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing
18+
for reference types
1819

1920
Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you
2021
found a bug with Miri, we'd appreciate if you tell us and we'll add it to the
@@ -47,6 +48,7 @@ program, and cannot run all programs:
4748
[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md
4849
[`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html
4950
[`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html
51+
[Stacked Borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md
5052

5153

5254
## Using Miri
@@ -152,10 +154,13 @@ Several `-Z` flags are relevant for Miri:
152154
**NOTE**: This entropy is not good enough for cryptographic use! Do not
153155
generate secret keys in Miri or perform other kinds of cryptographic
154156
operations that rely on proper random numbers.
155-
* `-Zmiri-disable-validation` disables enforcing validity invariants and
156-
reference aliasing rules, which are enforced by default. This is mostly
157-
useful for debugging. It means Miri will miss bugs in your program. However,
158-
this can also help to make Miri run faster.
157+
* `-Zmiri-disable-validation` disables enforcing validity invariants, which are
158+
enforced by default. This is mostly useful for debugging. It means Miri will
159+
miss bugs in your program. However, this can also help to make Miri run
160+
faster.
161+
* `-Zmiri-disable-stacked-borrows` disables checking the experimental
162+
[Stacked Borrows] aliasing rules. This can make Miri run faster, but it also
163+
means no aliasing violations will be detected.
159164
* `-Zmiri-disable-isolation` disables host host isolation. As a consequence,
160165
the program has access to host resources such as environment variables, file
161166
systems, and randomness.
@@ -234,7 +239,7 @@ Definite bugs found:
234239
* [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251)
235240
* [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73)
236241

237-
Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment):
242+
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
238243

239244
* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161)
240245
* [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431)

src/bin/miri.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ fn main() {
130130

131131
// Parse our arguments and split them across `rustc` and `miri`.
132132
let mut validate = true;
133+
let mut stacked_borrows = true;
133134
let mut communicate = false;
134135
let mut ignore_leaks = false;
135136
let mut seed: Option<u64> = None;
@@ -150,6 +151,9 @@ fn main() {
150151
"-Zmiri-disable-validation" => {
151152
validate = false;
152153
}
154+
"-Zmiri-disable-stacked-borrows" => {
155+
stacked_borrows = false;
156+
}
153157
"-Zmiri-disable-isolation" => {
154158
communicate = true;
155159
}
@@ -229,6 +233,7 @@ fn main() {
229233
debug!("miri arguments: {:?}", miri_args);
230234
let miri_config = miri::MiriConfig {
231235
validate,
236+
stacked_borrows,
232237
communicate,
233238
ignore_leaks,
234239
excluded_env_vars,

src/eval.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ use crate::*;
1414
/// Configuration needed to spawn a Miri instance.
1515
#[derive(Clone)]
1616
pub struct MiriConfig {
17-
/// Determine if validity checking and Stacked Borrows are enabled.
17+
/// Determine if validity checking is enabled.
1818
pub validate: bool,
19+
/// Determines if Stacked Borrows is enabled.
20+
pub stacked_borrows: bool,
1921
/// Determines if communication with the host environment is enabled.
2022
pub communicate: bool,
2123
/// Determines if memory leaks should be ignored.
@@ -52,6 +54,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
5254
MemoryExtra::new(
5355
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
5456
config.validate,
57+
config.stacked_borrows,
5558
config.tracked_pointer_tag,
5659
),
5760
);

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub use crate::mono_hash_map::MonoHashMap;
5656
pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
5757
pub use crate::range_map::RangeMap;
5858
pub use crate::stacked_borrows::{
59-
EvalContextExt as StackedBorEvalContextExt, GlobalState, Item, Permission, PtrId, Stack,
59+
EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack,
6060
Stacks, Tag,
6161
};
6262

src/machine.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use std::borrow::Cow;
55
use std::cell::RefCell;
66
use std::rc::Rc;
7+
use std::num::NonZeroU64;
78

89
use rand::rngs::StdRng;
910

@@ -63,14 +64,14 @@ impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
6364
/// Extra per-allocation data
6465
#[derive(Debug, Clone)]
6566
pub struct AllocExtra {
66-
/// Stacked Borrows state is only added if validation is enabled.
67+
/// Stacked Borrows state is only added if it is enabled.
6768
pub stacked_borrows: Option<stacked_borrows::AllocExtra>,
6869
}
6970

7071
/// Extra global memory data
7172
#[derive(Clone, Debug)]
7273
pub struct MemoryExtra {
73-
pub stacked_borrows: stacked_borrows::MemoryExtra,
74+
pub stacked_borrows: Option<stacked_borrows::MemoryExtra>,
7475
pub intptrcast: intptrcast::MemoryExtra,
7576

7677
/// The random number generator used for resolving non-determinism.
@@ -81,9 +82,14 @@ pub struct MemoryExtra {
8182
}
8283

8384
impl MemoryExtra {
84-
pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option<PtrId>) -> Self {
85+
pub fn new(rng: StdRng, validate: bool, stacked_borrows: bool, tracked_pointer_tag: Option<PtrId>) -> Self {
86+
let stacked_borrows = if stacked_borrows {
87+
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag))))
88+
} else {
89+
None
90+
};
8591
MemoryExtra {
86-
stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))),
92+
stacked_borrows,
8793
intptrcast: Default::default(),
8894
rng: RefCell::new(rng),
8995
validate,
@@ -299,27 +305,27 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
299305
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
300306
let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
301307
let alloc = alloc.into_owned();
302-
let (stacks, base_tag) = if memory_extra.validate {
308+
let (stacks, base_tag) = if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() {
303309
let (stacks, base_tag) = Stacks::new_allocation(
304310
id,
305311
alloc.size,
306-
Rc::clone(&memory_extra.stacked_borrows),
312+
Rc::clone(stacked_borrows),
307313
kind,
308314
);
309315
(Some(stacks), base_tag)
310316
} else {
311317
// No stacks, no tag.
312318
(None, Tag::Untagged)
313319
};
314-
let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut();
320+
let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut());
315321
let alloc: Allocation<Tag, Self::AllocExtra> = alloc.with_tags_and_extra(
316322
|alloc| {
317-
if !memory_extra.validate {
318-
Tag::Untagged
319-
} else {
323+
if let Some(stacked_borrows) = stacked_borrows.as_mut() {
320324
// Only statics may already contain pointers at this point
321325
assert_eq!(kind, MiriMemoryKind::Static.into());
322326
stacked_borrows.static_base_ptr(alloc)
327+
} else {
328+
Tag::Untagged
323329
}
324330
},
325331
AllocExtra { stacked_borrows: stacks },
@@ -329,10 +335,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
329335

330336
#[inline(always)]
331337
fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag {
332-
if !memory_extra.validate {
333-
Tag::Untagged
338+
if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() {
339+
stacked_borrows.borrow_mut().static_base_ptr(id)
334340
} else {
335-
memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id)
341+
Tag::Untagged
336342
}
337343
}
338344

@@ -342,7 +348,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
342348
kind: mir::RetagKind,
343349
place: PlaceTy<'tcx, Tag>,
344350
) -> InterpResult<'tcx> {
345-
if !Self::enforce_validity(ecx) {
351+
if ecx.memory.extra.stacked_borrows.is_none() {
346352
// No tracking.
347353
Ok(())
348354
} else {
@@ -352,8 +358,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
352358

353359
#[inline(always)]
354360
fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> {
361+
let call_id = ecx.memory.extra.stacked_borrows.as_ref().map_or(
362+
NonZeroU64::new(1).unwrap(),
363+
|stacked_borrows| stacked_borrows.borrow_mut().new_call(),
364+
);
355365
Ok(FrameData {
356-
call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(),
366+
call_id,
357367
catch_panic: None,
358368
})
359369
}

src/shims/panic.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
146146
} else {
147147
StackPopInfo::Normal
148148
};
149-
this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id);
149+
if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() {
150+
stacked_borrows.borrow_mut().end_call(extra.call_id);
151+
}
150152
Ok(res)
151153
}
152154

src/stacked_borrows.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
575575
// breaking `Rc::from_raw`.
576576
RefKind::Raw { .. } => Tag::Untagged,
577577
// All other pointesr are properly tracked.
578-
_ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()),
578+
_ => Tag::Tagged(this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr()),
579579
};
580580

581581
// Reborrow.

tests/compile-fail/modifying_constants.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// This should fail even without validation
2-
// compile-flags: -Zmiri-disable-validation
1+
// This should fail even without validation/SB
2+
// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
fn main() {
55
let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee

tests/compile-fail/reference_to_packed.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// This should fail even without validation
2-
// compile-flags: -Zmiri-disable-validation
1+
// This should fail even without validation/SB
2+
// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
#![allow(dead_code, unused_variables)]
55

tests/compile-fail/stack_free.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// Validation changes why we fail
2-
// compile-flags: -Zmiri-disable-validation
1+
// Validation/SB changes why we fail
2+
// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
33

44
// error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind
55

0 commit comments

Comments
 (0)