Skip to content

Commit 61f2076

Browse files
authored
Merge branch 'master' into stacked-borrows-2-phase
2 parents b6e5822 + 5bde40c commit 61f2076

File tree

11 files changed

+114
-59
lines changed

11 files changed

+114
-59
lines changed

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2018-11-30
1+
nightly-2018-12-03

src/bin/cargo-miri.rs

+3
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ fn setup(ask_user: bool) {
155155
File::create(dir.join("Xargo.toml")).unwrap()
156156
.write_all(br#"
157157
[dependencies.std]
158+
default_features = false
159+
# We need the `panic_unwind` feature because we use the `unwind` panic strategy.
160+
# Using `abort` works for libstd, but then libtest will not compile.
158161
features = ["panic_unwind"]
159162
160163
[dependencies.test]

src/lib.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -310,26 +310,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
310310

311311
const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);
312312

313+
#[inline(always)]
313314
fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
314-
if !ecx.machine.validate {
315-
return false;
316-
}
317-
318-
// Some functions are whitelisted until we figure out how to fix them.
319-
// We walk up the stack a few frames to also cover their callees.
320-
const WHITELIST: &[(&str, &str)] = &[
321-
// Uses mem::uninitialized
322-
("std::sys::windows::mutex::Mutex::", ""),
323-
];
324-
for frame in ecx.stack().iter()
325-
.rev().take(3)
326-
{
327-
let name = frame.instance.to_string();
328-
if WHITELIST.iter().any(|(prefix, suffix)| name.starts_with(prefix) && name.ends_with(suffix)) {
329-
return false;
330-
}
331-
}
332-
true
315+
ecx.machine.validate
333316
}
334317

335318
/// Returns Ok() when the function was handled, fail otherwise

src/stacked_borrows.rs

+20-15
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,28 @@ impl<'tcx> Stack {
303303
/// is met: We cannot push `Uniq` onto frozen stacks.
304304
/// `kind` indicates which kind of reference is being created.
305305
fn create(&mut self, bor: Borrow, kind: RefKind) {
306-
if self.frozen_since.is_some() {
307-
// A frozen location? Possible if we create a barrier, then push again.
308-
assert!(bor.is_shared(), "We should never try creating a unique borrow for a frozen stack");
309-
trace!("create: Not doing anything on frozen location");
306+
// When creating a frozen reference, freeze. This ensures F1.
307+
// We also do *not* push anything else to the stack, making sure that no nother kind
308+
// of access (like writing through raw pointers) is permitted.
309+
if kind == RefKind::Frozen {
310+
let bor_t = match bor {
311+
Borrow::Shr(Some(t)) => t,
312+
_ => bug!("Creating illegal borrow {:?} for frozen ref", bor),
313+
};
314+
// It is possible that we already are frozen (e.g. if we just pushed a barrier,
315+
// the redundancy check would not have kicked in).
316+
match self.frozen_since {
317+
Some(loc_t) => assert!(loc_t <= bor_t, "Trying to freeze location for longer than it was already frozen"),
318+
None => {
319+
trace!("create: Freezing");
320+
self.frozen_since = Some(bor_t);
321+
}
322+
}
310323
return;
311324
}
312-
// First, push. We do this even if we will later freeze, because we
313-
// will allow mutation of shared data at the expense of unfreezing.
325+
assert!(self.frozen_since.is_none(), "Trying to create non-frozen reference to frozen location");
326+
327+
// Push new item to the stack.
314328
let itm = match bor {
315329
Borrow::Uniq(t) => BorStackItem::Uniq(t),
316330
Borrow::Shr(_) => BorStackItem::Shr,
@@ -325,15 +339,6 @@ impl<'tcx> Stack {
325339
trace!("create: Pushing {:?}", itm);
326340
self.borrows.push(itm);
327341
}
328-
// Then, maybe freeze. This is part 2 of ensuring F1.
329-
if kind == RefKind::Frozen {
330-
let bor_t = match bor {
331-
Borrow::Shr(Some(t)) => t,
332-
_ => bug!("Creating illegal borrow {:?} for frozen ref", bor),
333-
};
334-
trace!("create: Freezing");
335-
self.frozen_since = Some(bor_t);
336-
}
337342
}
338343

339344
/// Add a barrier

tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ fn main() {
33
// Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref.
44
let r#ref = &target; // freeze
55
let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag
6-
unsafe { *ptr = 42; }
7-
let _val = *r#ref; //~ ERROR is not frozen
6+
unsafe { *ptr = 42; } //~ ERROR does not exist on the stack
7+
let _val = *r#ref;
88
}

tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ fn foo(_: &i32) {}
33

44
fn main() {
55
let x = &mut 42;
6-
let xraw = &*x as *const _ as *mut _;
6+
let xraw = x as *mut _;
77
let xref = unsafe { &*xraw };
88
unsafe { *xraw = 42 }; // unfreeze
99
foo(xref); //~ ERROR is not frozen
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn foo(x: &mut i32) -> i32 {
2+
*x = 5;
3+
unknown_code(&*x);
4+
*x // must return 5
5+
}
6+
7+
fn main() {
8+
println!("{}", foo(&mut 0));
9+
}
10+
11+
// If we replace the `*const` by `&`, my current dev version of miri
12+
// *does* find the problem, but not for a good reason: It finds it because
13+
// of barriers, and we shouldn't rely on unknown code using barriers.
14+
fn unknown_code(x: *const i32) {
15+
unsafe { *(x as *mut i32) = 7; } //~ ERROR barrier
16+
}

tests/compiletest.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,33 @@ fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
124124
path.metadata().map(|m| m.is_dir()).unwrap_or(false)
125125
}
126126

127-
fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
127+
fn target_has_std<P: Into<PathBuf>>(path: P) -> bool {
128+
let mut path = path.into();
129+
path.push("lib");
130+
std::fs::read_dir(path)
131+
.expect("invalid target")
132+
.map(|entry| entry.unwrap())
133+
.filter(|entry| entry.file_type().unwrap().is_file())
134+
.filter_map(|entry| entry.file_name().into_string().ok())
135+
.any(|file_name| file_name.starts_with("libstd") && file_name.ends_with(".rlib"))
136+
}
137+
138+
139+
fn for_all_targets<F: FnMut(String)>(sysroot: &Path, f: F) {
128140
let target_dir = sysroot.join("lib").join("rustlib");
129-
for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
130-
let entry = entry.unwrap();
131-
if !is_target_dir(entry.path()) {
132-
continue;
133-
}
134-
let target = entry.file_name().into_string().unwrap();
135-
f(target);
141+
let mut targets = std::fs::read_dir(target_dir)
142+
.expect("invalid sysroot")
143+
.map(|entry| entry.unwrap())
144+
.filter(|entry| is_target_dir(entry.path()))
145+
.filter(|entry| target_has_std(entry.path()))
146+
.map(|entry| entry.file_name().into_string().unwrap())
147+
.peekable();
148+
149+
if targets.peek().is_none() {
150+
panic!("No valid targets found");
136151
}
152+
153+
targets.for_each(f);
137154
}
138155

139156
fn get_sysroot() -> PathBuf {

tests/run-pass-fullmir/vecdeque.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// FIXME: Validation disabled until https://github.com/rust-lang/rust/pull/56161 lands
2+
// compile-flags: -Zmiri-disable-validation
3+
14
use std::collections::VecDeque;
25

36
fn main() {

tests/run-pass/refcell.rs

+23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ fn aliasing_mut_and_shr() {
3939
*aliasing += 4;
4040
let _shr = &*rc;
4141
*aliasing += 4;
42+
// also turning this into a frozen ref now must work
43+
let aliasing = &*aliasing;
44+
let _val = *aliasing;
45+
let _escape_to_raw = rc as *const _; // this must NOT unfreeze
46+
let _val = *aliasing;
47+
let _shr = &*rc; // this must NOT unfreeze
48+
let _val = *aliasing;
4249
}
4350

4451
let rc = RefCell::new(23);
@@ -48,7 +55,23 @@ fn aliasing_mut_and_shr() {
4855
assert_eq!(*rc.borrow(), 23+12);
4956
}
5057

58+
fn aliasing_frz_and_shr() {
59+
fn inner(rc: &RefCell<i32>, aliasing: &i32) {
60+
let _val = *aliasing;
61+
let _escape_to_raw = rc as *const _; // this must NOT unfreeze
62+
let _val = *aliasing;
63+
let _shr = &*rc; // this must NOT unfreeze
64+
let _val = *aliasing;
65+
}
66+
67+
let rc = RefCell::new(23);
68+
let bshr = rc.borrow();
69+
inner(&rc, &*bshr);
70+
assert_eq!(*rc.borrow(), 23);
71+
}
72+
5173
fn main() {
5274
lots_of_funny_borrows();
5375
aliasing_mut_and_shr();
76+
aliasing_frz_and_shr();
5477
}

tests/run-pass/stacked-borrows.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ fn main() {
44
read_does_not_invalidate1();
55
read_does_not_invalidate2();
66
ref_raw_int_raw();
7-
mut_shr_raw();
87
mut_raw_then_mut_shr();
8+
mut_shr_then_mut_raw();
99
mut_raw_mut();
1010
partially_invalidate_mut();
11+
drop_after_sharing();
1112
}
1213

1314
// Deref a raw ptr to access a field of a large struct, where the field
@@ -53,18 +54,6 @@ fn ref_raw_int_raw() {
5354
assert_eq!(unsafe { *xraw }, 3);
5455
}
5556

56-
// Creating a raw from a `&mut` through an `&` works, even if we
57-
// write through that raw.
58-
fn mut_shr_raw() {
59-
let mut x = 2;
60-
{
61-
let xref = &mut x;
62-
let xraw = &*xref as *const i32 as *mut i32;
63-
unsafe { *xraw = 4; }
64-
}
65-
assert_eq!(x, 4);
66-
}
67-
6857
// Escape a mut to raw, then share the same mut and use the share, then the raw.
6958
// That should work.
7059
fn mut_raw_then_mut_shr() {
@@ -77,6 +66,16 @@ fn mut_raw_then_mut_shr() {
7766
assert_eq!(x, 4);
7867
}
7968

69+
// Create first a shared reference and then a raw pointer from a `&mut`
70+
// should permit mutation through that raw pointer.
71+
fn mut_shr_then_mut_raw() {
72+
let xref = &mut 2;
73+
let _xshr = &*xref;
74+
let xraw = xref as *mut _;
75+
unsafe { *xraw = 3; }
76+
assert_eq!(*xref, 3);
77+
}
78+
8079
// Ensure that if we derive from a mut a raw, and then from that a mut,
8180
// and then read through the original mut, that does not invalidate the raw.
8281
// This shows that the read-exception for `&mut` applies even if the `Shr` item
@@ -107,3 +106,9 @@ fn partially_invalidate_mut() {
107106
*shard += 1; // so we can still use `shard`.
108107
assert_eq!(*data, (1, 1));
109108
}
109+
110+
// Make sure that we can handle the situation where a loaction is frozen when being dropped.
111+
fn drop_after_sharing() {
112+
let x = String::from("hello!");
113+
let _len = x.len();
114+
}

0 commit comments

Comments
 (0)