## Running Miri
```sh
-cargo +nightly run tests/run-pass/vecs.rs # Or whatever test you like.
+cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like.
```
+We have to disable validation because that can lead to errors when libstd is not
+compiled the right way.
+
## Running Miri with full libstd
-Per default libstd does not contain the MIR of non-polymorphic functions. When
-Miri hits a call to such a function, execution terminates. To fix this, it is
-possible to compile libstd with full MIR:
+Per default libstd does not contain the MIR of non-polymorphic functions, and
+also does not contain some extra MIR statements that miri needs for validation.
+When Miri hits a call to such a function, execution terminates, and even when
+the MIR is present, validation can fail. To fix this, it is possible to compile
+libstd with full MIR:
```sh
rustup component add --toolchain nightly rust-src
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(core_intrinsics)]
+
+//error-pattern: copy_nonoverlapping called on overlapping ranges
+
+fn main() {
+ let mut data = [0u8; 16];
+ unsafe {
+ let a = data.as_mut_ptr();
+ let b = a.wrapping_offset(1) as *mut _;
+ std::ptr::copy_nonoverlapping(a, b, 2);
+ }
+}
--- /dev/null
+// ignore-windows: We do not check leaks on Windows
+// ignore-macos: We do not check leaks on macOS
+
+//error-pattern: the evaluated program leaked memory
+
+use std::rc::Rc;
+use std::cell::RefCell;
+
+struct Dummy(Rc<RefCell<Option<Dummy>>>);
+
+fn main() {
+ let x = Dummy(Rc::new(RefCell::new(None)));
+ let y = Dummy(x.0.clone());
+ *x.0.borrow_mut() = Some(y);
+}
--- /dev/null
+#![allow(unused_variables)]
+
+// This makes a ref that was passed to us via &mut alias with things it should not alias with
+fn retarget(x: &mut &u32, target: &mut u32) {
+ unsafe { *x = &mut *(target as *mut _); }
+}
+
+fn main() {
+ let target = &mut 42;
+ let mut target_alias = &42; // initial dummy value
+ retarget(&mut target_alias, target);
+ // now `target_alias` points to the same thing as `target`
+ *target = 13;
+ let _val = *target_alias; //~ ERROR does not exist on the stack
+}
--- /dev/null
+// ignore-test validation_op is disabled
+
+#![allow(unused_variables)]
+
+mod safe {
+ pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR: in conflict with lock WriteLock
+}
+
+fn main() {
+ let x = &mut 0 as *mut _;
+ unsafe { safe::safe(&mut *x, &mut *x) };
+}
--- /dev/null
+// ignore-test validation_op is disabled
+
+#![allow(unused_variables)]
+
+mod safe {
+ pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR: in conflict with lock ReadLock
+}
+
+fn main() {
+ let x = &mut 0 as *mut _;
+ unsafe { safe::safe(&*x, &mut *x) };
+}
--- /dev/null
+// ignore-test validation_op is disabled
+
+#![allow(unused_variables)]
+
+mod safe {
+ pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR: in conflict with lock WriteLock
+}
+
+fn main() {
+ let x = &mut 0 as *mut _;
+ unsafe { safe::safe(&mut *x, &*x) };
+}
--- /dev/null
+// ignore-test validation_op is disabled
+
+#![allow(unused_variables)]
+
+mod safe {
+ use std::cell::Cell;
+
+ // Make sure &mut UnsafeCell also has a lock to it
+ pub fn safe(x: &mut Cell<i32>, y: &i32) {} //~ ERROR: in conflict with lock WriteLock
+}
+
+fn main() {
+ let x = &mut 0 as *mut _;
+ unsafe { safe::safe(&mut *(x as *mut _), &*x) };
+}
--- /dev/null
+// error-pattern: mutable reference with frozen tag
+
+mod safe {
+ use std::slice::from_raw_parts_mut;
+
+ pub fn as_mut_slice<T>(self_: &Vec<T>) -> &mut [T] {
+ unsafe {
+ from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len())
+ }
+ }
+}
+
+fn main() {
+ let v = vec![0,1,2];
+ let _v1 = safe::as_mut_slice(&v);
+/*
+ let v2 = safe::as_mut_slice(&v);
+ v1[1] = 5;
+ v1[1] = 6;
+*/
+}
--- /dev/null
+#![allow(unused_variables)]
+
+mod safe {
+ use std::slice::from_raw_parts_mut;
+
+ pub fn split_at_mut<T>(self_: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
+ let len = self_.len();
+ let ptr = self_.as_mut_ptr();
+
+ unsafe {
+ assert!(mid <= len);
+
+ (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid"
+ from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
+ }
+ }
+}
+
+fn main() {
+ let mut array = [1,2,3,4];
+ let (a, b) = safe::split_at_mut(&mut array, 0);
+ //~^ ERROR does not exist on the stack
+ a[1] = 5;
+ b[1] = 6;
+}
--- /dev/null
+// A callee may not read the destination of our `&mut` without
+// us noticing.
+
+fn main() {
+ let mut x = 15;
+ let xraw = &mut x as *mut _;
+ let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay...
+ callee(xraw);
+ let _val = *xref; // ...but any use of raw will invalidate our ref.
+ //~^ ERROR: does not exist on the stack
+}
+
+fn callee(xraw: *mut i32) {
+ let _val = unsafe { *xraw };
+}
--- /dev/null
+// A callee may not read the destination of our `&mut` without
+// us noticing.
+
+fn main() {
+ let mut x = 15;
+ let xraw = &mut x as *mut _;
+ let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay...
+ callee(xraw);
+ let _val = *xref; // ...but any use of raw will invalidate our ref.
+ //~^ ERROR: does not exist on the stack
+}
+
+fn callee(xraw: *mut i32) {
+ // We are a bit sneaky: We first create a shared ref, exploiting the reborrowing rules,
+ // and then we read through that.
+ let shr = unsafe { &*xraw };
+ let _val = *shr;
+}
--- /dev/null
+#![feature(untagged_unions)]
+// A callee may not read the destination of our `&mut` without
+// us noticing.
+// Thise code got carefully checked to not introduce any reborrows
+// that are not explicit in the source. Let's hope the compiler does not break this later!
+
+use std::mem;
+
+fn main() {
+ let mut x: i32 = 15;
+ let xref1 = &mut x;
+ let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) };
+ let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay...
+ callee(xref1_sneaky);
+ let _val = *xref2; // ...but any use of it will invalidate our ref.
+ //~^ ERROR: does not exist on the stack
+}
+
+fn callee(xref1: usize) {
+ // Transmuting through a union to avoid retagging
+ union UsizeToRef {
+ from: usize,
+ to: &'static mut i32,
+ }
+ let xref1 = UsizeToRef { from: xref1 };
+ // Doing the deref and the transmute (through the union) in the same place expression
+ // should avoid retagging.
+ let _val = unsafe { *xref1.to };
+}
--- /dev/null
+// Using a raw invalidates derived `&mut` even for reading.
+fn main() {
+ let mut x = 2;
+ let xref1 = &mut x;
+ let xraw = xref1 as *mut _;
+ let xref2 = unsafe { &mut *xraw };
+ let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs
+ let _illegal = *xref2; //~ ERROR does not exist on the stack
+}
--- /dev/null
+// We *can* have aliasing &RefCell<T> and &mut T, but we cannot read through the former.
+// Else we couldn't optimize based on the assumption that `xref` below is truly unique.
+
+use std::cell::RefCell;
+use std::{mem, ptr};
+
+fn main() {
+ let rc = RefCell::new(0);
+ let mut refmut = rc.borrow_mut();
+ let xref: &mut i32 = &mut *refmut;
+ let xshr = &rc; // creating this is okay
+ let _val = *xref; // we can even still use our mutable reference
+ mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref
+ let _val = *xref; // the mutable one is dead and gone
+ //~^ ERROR does not exist on the stack
+}
--- /dev/null
+fn evil(x: &u32) {
+ // mutating shared ref without `UnsafeCell`
+ let x : *mut u32 = x as *const _ as *mut _;
+ unsafe { *x = 42; }
+}
+
+fn main() {
+ let target = Box::new(42); // has an implicit raw
+ let ref_ = &*target;
+ evil(ref_); // invalidates shared ref, activates raw
+ let _x = *ref_; //~ ERROR is not frozen
+}
--- /dev/null
+// We fail to detect this when neither this nor libstd are optimized/have retagging.
+// FIXME: Investigate that.
+// compile-flags: -Zmir-opt-level=0
+
+#![allow(unused_variables)]
+
+fn main() {
+ let target = &mut 42;
+ let target2 = target as *mut _;
+ drop(&mut *target); // reborrow
+ // Now make sure our ref is still the only one.
+ unsafe { *target2 = 13; } //~ ERROR does not exist on the stack
+ let _val = *target;
+}
--- /dev/null
+fn main() {
+ let target = 42;
+ // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref.
+ let r#ref = ⌖ // freeze
+ let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag
+ unsafe { *ptr = 42; }
+ let _val = *r#ref; //~ ERROR is not frozen
+}
--- /dev/null
+use std::mem;
+
+fn main() {
+ let mut target = 42;
+ // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location.
+ // Even just creating it unfreezes.
+ let raw = &mut target as *mut _; // let this leak to raw
+ let reference = unsafe { &*raw }; // freeze
+ let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag
+ let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag
+ // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing.
+ let _val = *reference; //~ ERROR is not frozen
+}
--- /dev/null
+// A callee may not write to the destination of our `&mut` without
+// us noticing.
+
+fn main() {
+ let mut x = 15;
+ let xraw = &mut x as *mut _;
+ let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay...
+ callee(xraw);
+ let _val = *xref; // ...but any use of raw will invalidate our ref.
+ //~^ ERROR: does not exist on the stack
+}
+
+fn callee(xraw: *mut i32) {
+ unsafe { *xraw = 15 };
+}
--- /dev/null
+// Make sure that we cannot load from memory a `&mut` that got already invalidated.
+fn main() {
+ let x = &mut 42;
+ let xraw = x as *mut _;
+ let xref = unsafe { &mut *xraw };
+ let xref_in_mem = Box::new(xref);
+ let _val = unsafe { *xraw }; // invalidate xref
+ let _val = *xref_in_mem; //~ ERROR does not exist on the stack
+}
--- /dev/null
+// Make sure that we cannot load from memory a `&` that got already invalidated.
+fn main() {
+ let x = &mut 42;
+ let xraw = x as *mut _;
+ let xref = unsafe { &*xraw };
+ let xref_in_mem = Box::new(xref);
+ unsafe { *xraw = 42 }; // unfreeze
+ let _val = *xref_in_mem; //~ ERROR is not frozen
+}
--- /dev/null
+fn demo_mut_advanced_unique(our: &mut i32) -> i32 {
+ unknown_code_1(&*our);
+
+ // This "re-asserts" uniqueness of the reference: After writing, we know
+ // our tag is at the top of the stack.
+ *our = 5;
+
+ unknown_code_2();
+
+ // We know this will return 5
+ *our
+}
+
+// Now comes the evil context
+use std::ptr;
+
+static mut LEAK: *mut i32 = ptr::null_mut();
+
+fn unknown_code_1(x: &i32) { unsafe {
+ LEAK = x as *const _ as *mut _;
+} }
+
+fn unknown_code_2() { unsafe {
+ *LEAK = 7; //~ ERROR does not exist on the stack
+} }
+
+fn main() {
+ assert_eq!(demo_mut_advanced_unique(&mut 0), 5);
+}
--- /dev/null
+fn main() {
+ let mut x = 0;
+ let y: *const i32 = &x;
+ x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local
+
+ assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack
+
+ assert_eq!(x, 1);
+}
--- /dev/null
+// Make sure that we cannot pass by argument a `&mut` that got already invalidated.
+fn foo(_: &mut i32) {}
+
+fn main() {
+ let x = &mut 42;
+ let xraw = x as *mut _;
+ let xref = unsafe { &mut *xraw };
+ let _val = unsafe { *xraw }; // invalidate xref
+ foo(xref); //~ ERROR does not exist on the stack
+}
--- /dev/null
+// Make sure that we cannot pass by argument a `&` that got already invalidated.
+fn foo(_: &i32) {}
+
+fn main() {
+ let x = &mut 42;
+ let xraw = &*x as *const _ as *mut _;
+ let xref = unsafe { &*xraw };
+ unsafe { *xraw = 42 }; // unfreeze
+ foo(xref); //~ ERROR is not frozen
+}
--- /dev/null
+#![allow(unused_variables)]
+
+static mut PTR: *mut u8 = 0 as *mut _;
+
+fn fun1(x: &mut u8) {
+ unsafe {
+ PTR = x;
+ }
+}
+
+fn fun2() {
+ // Now we use a pointer we are not allowed to use
+ let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack
+}
+
+fn main() {
+ let val = &mut 0; // FIXME: This should also work with a local variable, but currently it does not.
+ fun1(val);
+ *val = 2; // this invalidates any raw ptrs `fun1` might have created.
+ fun2(); // if they now use a raw ptr they break our reference
+}
--- /dev/null
+// Make sure that we cannot return a `&mut` that got already invalidated.
+fn foo(x: &mut (i32, i32)) -> &mut i32 {
+ let xraw = x as *mut (i32, i32);
+ let ret = unsafe { &mut (*xraw).1 };
+ let _val = unsafe { *xraw }; // invalidate xref
+ ret //~ ERROR does not exist on the stack
+}
+
+fn main() {
+ foo(&mut (1, 2));
+}
--- /dev/null
+// Make sure that we cannot return a `&` that got already invalidated.
+fn foo(x: &mut (i32, i32)) -> &i32 {
+ let xraw = x as *mut (i32, i32);
+ let ret = unsafe { &(*xraw).1 };
+ unsafe { *xraw = (42, 23) }; // unfreeze
+ ret //~ ERROR is not frozen
+}
+
+fn main() {
+ foo(&mut (1, 2));
+}
--- /dev/null
+// FIXME still considering whether we are okay with this not being an error
+// ignore-test
+
+static X: usize = 5;
+
+#[allow(mutable_transmutes)]
+fn main() {
+ let _x = unsafe {
+ std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR mutable reference with frozen tag
+ };
+}
--- /dev/null
+// Make sure we cannot use raw ptrs that got transmuted from mutable references
+// (i.e, no EscapeToRaw happened).
+// We could, in principle, to EscapeToRaw lazily to allow this code, but that
+// would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in
+// `run-pass/stacked-borrows.rs`), and thus increase overall complexity.
+use std::mem;
+
+fn main() {
+ let mut x: i32 = 42;
+ let raw: *mut i32 = unsafe { mem::transmute(&mut x) };
+ unsafe { *raw = 13; } //~ ERROR does not exist on the stack
+}
--- /dev/null
+// Make sure we cannot use raw ptrs to access a local that
+// we took the direct address of.
+fn main() {
+ let mut x = 42;
+ let raw = &mut x as *mut i32 as usize as *mut i32;
+ let _ptr = &mut x;
+ unsafe { *raw = 13; } //~ ERROR does not exist on the stack
+}
--- /dev/null
+#![feature(core_intrinsics)]
+
+use std::mem;
+
+fn main() {
+ let x: Option<Box<[u8]>> = unsafe {
+ let z = std::intrinsics::add_with_overflow(0usize, 0usize);
+ std::mem::transmute::<(usize, bool), Option<Box<[u8]>>>(z)
+ };
+ let y = &x;
+ // Now read this bytewise. There should be (ptr_size+1) def bytes followed by (ptr_size-1) undef bytes (the padding after the bool) in there.
+ let z : *const u8 = y as *const _ as *const _;
+ let first_undef = mem::size_of::<usize>() as isize + 1;
+ for i in 0..first_undef {
+ let byte = unsafe { *z.offset(i) };
+ assert_eq!(byte, 0);
+ }
+ let v = unsafe { *z.offset(first_undef) };
+ if v == 0 {} //~ ERROR attempted to read undefined bytes
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(core_intrinsics)]
-
-//error-pattern: copy_nonoverlapping called on overlapping ranges
-
-fn main() {
- let mut data = [0u8; 16];
- unsafe {
- let a = data.as_mut_ptr();
- let b = a.wrapping_offset(1) as *mut _;
- std::ptr::copy_nonoverlapping(a, b, 2);
- }
-}
+++ /dev/null
-// ignore-windows: We do not check leaks on Windows
-// ignore-macos: We do not check leaks on macOS
-
-//error-pattern: the evaluated program leaked memory
-
-use std::rc::Rc;
-use std::cell::RefCell;
-
-struct Dummy(Rc<RefCell<Option<Dummy>>>);
-
-fn main() {
- let x = Dummy(Rc::new(RefCell::new(None)));
- let y = Dummy(x.0.clone());
- *x.0.borrow_mut() = Some(y);
-}
+++ /dev/null
-#![allow(unused_variables)]
-
-// This makes a ref that was passed to us via &mut alias with things it should not alias with
-fn retarget(x: &mut &u32, target: &mut u32) {
- unsafe { *x = &mut *(target as *mut _); }
-}
-
-fn main() {
- let target = &mut 42;
- let mut target_alias = &42; // initial dummy value
- retarget(&mut target_alias, target);
- // now `target_alias` points to the same thing as `target`
- *target = 13;
- let _val = *target_alias; //~ ERROR does not exist on the stack
-}
+++ /dev/null
-// ignore-test validation_op is disabled
-
-#![allow(unused_variables)]
-
-mod safe {
- pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR: in conflict with lock WriteLock
-}
-
-fn main() {
- let x = &mut 0 as *mut _;
- unsafe { safe::safe(&mut *x, &mut *x) };
-}
+++ /dev/null
-// ignore-test validation_op is disabled
-
-#![allow(unused_variables)]
-
-mod safe {
- pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR: in conflict with lock ReadLock
-}
-
-fn main() {
- let x = &mut 0 as *mut _;
- unsafe { safe::safe(&*x, &mut *x) };
-}
+++ /dev/null
-// ignore-test validation_op is disabled
-
-#![allow(unused_variables)]
-
-mod safe {
- pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR: in conflict with lock WriteLock
-}
-
-fn main() {
- let x = &mut 0 as *mut _;
- unsafe { safe::safe(&mut *x, &*x) };
-}
+++ /dev/null
-// ignore-test validation_op is disabled
-
-#![allow(unused_variables)]
-
-mod safe {
- use std::cell::Cell;
-
- // Make sure &mut UnsafeCell also has a lock to it
- pub fn safe(x: &mut Cell<i32>, y: &i32) {} //~ ERROR: in conflict with lock WriteLock
-}
-
-fn main() {
- let x = &mut 0 as *mut _;
- unsafe { safe::safe(&mut *(x as *mut _), &*x) };
-}
+++ /dev/null
-// error-pattern: mutable reference with frozen tag
-
-mod safe {
- use std::slice::from_raw_parts_mut;
-
- pub fn as_mut_slice<T>(self_: &Vec<T>) -> &mut [T] {
- unsafe {
- from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len())
- }
- }
-}
-
-fn main() {
- let v = vec![0,1,2];
- let _v1 = safe::as_mut_slice(&v);
-/*
- let v2 = safe::as_mut_slice(&v);
- v1[1] = 5;
- v1[1] = 6;
-*/
-}
+++ /dev/null
-#![allow(unused_variables)]
-
-mod safe {
- use std::slice::from_raw_parts_mut;
-
- pub fn split_at_mut<T>(self_: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
- let len = self_.len();
- let ptr = self_.as_mut_ptr();
-
- unsafe {
- assert!(mid <= len);
-
- (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid"
- from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
- }
- }
-}
-
-fn main() {
- let mut array = [1,2,3,4];
- let (a, b) = safe::split_at_mut(&mut array, 0);
- //~^ ERROR does not exist on the stack
- a[1] = 5;
- b[1] = 6;
-}
+++ /dev/null
-// A callee may not read the destination of our `&mut` without
-// us noticing.
-
-fn main() {
- let mut x = 15;
- let xraw = &mut x as *mut _;
- let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay...
- callee(xraw);
- let _val = *xref; // ...but any use of raw will invalidate our ref.
- //~^ ERROR: does not exist on the stack
-}
-
-fn callee(xraw: *mut i32) {
- let _val = unsafe { *xraw };
-}
+++ /dev/null
-// A callee may not read the destination of our `&mut` without
-// us noticing.
-
-fn main() {
- let mut x = 15;
- let xraw = &mut x as *mut _;
- let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay...
- callee(xraw);
- let _val = *xref; // ...but any use of raw will invalidate our ref.
- //~^ ERROR: does not exist on the stack
-}
-
-fn callee(xraw: *mut i32) {
- // We are a bit sneaky: We first create a shared ref, exploiting the reborrowing rules,
- // and then we read through that.
- let shr = unsafe { &*xraw };
- let _val = *shr;
-}
+++ /dev/null
-#![feature(untagged_unions)]
-// A callee may not read the destination of our `&mut` without
-// us noticing.
-// Thise code got carefully checked to not introduce any reborrows
-// that are not explicit in the source. Let's hope the compiler does not break this later!
-
-use std::mem;
-
-fn main() {
- let mut x: i32 = 15;
- let xref1 = &mut x;
- let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) };
- let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay...
- callee(xref1_sneaky);
- let _val = *xref2; // ...but any use of it will invalidate our ref.
- //~^ ERROR: does not exist on the stack
-}
-
-fn callee(xref1: usize) {
- // Transmuting through a union to avoid retagging
- union UsizeToRef {
- from: usize,
- to: &'static mut i32,
- }
- let xref1 = UsizeToRef { from: xref1 };
- // Doing the deref and the transmute (through the union) in the same place expression
- // should avoid retagging.
- let _val = unsafe { *xref1.to };
-}
+++ /dev/null
-// Using a raw invalidates derived `&mut` even for reading.
-fn main() {
- let mut x = 2;
- let xref1 = &mut x;
- let xraw = xref1 as *mut _;
- let xref2 = unsafe { &mut *xraw };
- let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs
- let _illegal = *xref2; //~ ERROR does not exist on the stack
-}
+++ /dev/null
-// We *can* have aliasing &RefCell<T> and &mut T, but we cannot read through the former.
-// Else we couldn't optimize based on the assumption that `xref` below is truly unique.
-
-use std::cell::RefCell;
-use std::{mem, ptr};
-
-fn main() {
- let rc = RefCell::new(0);
- let mut refmut = rc.borrow_mut();
- let xref: &mut i32 = &mut *refmut;
- let xshr = &rc; // creating this is okay
- let _val = *xref; // we can even still use our mutable reference
- mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref
- let _val = *xref; // the mutable one is dead and gone
- //~^ ERROR does not exist on the stack
-}
+++ /dev/null
-fn evil(x: &u32) {
- // mutating shared ref without `UnsafeCell`
- let x : *mut u32 = x as *const _ as *mut _;
- unsafe { *x = 42; }
-}
-
-fn main() {
- let target = Box::new(42); // has an implicit raw
- let ref_ = &*target;
- evil(ref_); // invalidates shared ref, activates raw
- let _x = *ref_; //~ ERROR is not frozen
-}
+++ /dev/null
-// We fail to detect this when neither this nor libstd are optimized/have retagging.
-// FIXME: Investigate that.
-// compile-flags: -Zmir-opt-level=0
-
-#![allow(unused_variables)]
-
-fn main() {
- let target = &mut 42;
- let target2 = target as *mut _;
- drop(&mut *target); // reborrow
- // Now make sure our ref is still the only one.
- unsafe { *target2 = 13; } //~ ERROR does not exist on the stack
- let _val = *target;
-}
+++ /dev/null
-fn main() {
- let target = 42;
- // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref.
- let r#ref = ⌖ // freeze
- let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag
- unsafe { *ptr = 42; }
- let _val = *r#ref; //~ ERROR is not frozen
-}
+++ /dev/null
-use std::mem;
-
-fn main() {
- let mut target = 42;
- // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location.
- // Even just creating it unfreezes.
- let raw = &mut target as *mut _; // let this leak to raw
- let reference = unsafe { &*raw }; // freeze
- let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag
- let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag
- // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing.
- let _val = *reference; //~ ERROR is not frozen
-}
+++ /dev/null
-// A callee may not write to the destination of our `&mut` without
-// us noticing.
-
-fn main() {
- let mut x = 15;
- let xraw = &mut x as *mut _;
- let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay...
- callee(xraw);
- let _val = *xref; // ...but any use of raw will invalidate our ref.
- //~^ ERROR: does not exist on the stack
-}
-
-fn callee(xraw: *mut i32) {
- unsafe { *xraw = 15 };
-}
+++ /dev/null
-// Make sure that we cannot load from memory a `&mut` that got already invalidated.
-fn main() {
- let x = &mut 42;
- let xraw = x as *mut _;
- let xref = unsafe { &mut *xraw };
- let xref_in_mem = Box::new(xref);
- let _val = unsafe { *xraw }; // invalidate xref
- let _val = *xref_in_mem; //~ ERROR does not exist on the stack
-}
+++ /dev/null
-// Make sure that we cannot load from memory a `&` that got already invalidated.
-fn main() {
- let x = &mut 42;
- let xraw = x as *mut _;
- let xref = unsafe { &*xraw };
- let xref_in_mem = Box::new(xref);
- unsafe { *xraw = 42 }; // unfreeze
- let _val = *xref_in_mem; //~ ERROR is not frozen
-}
+++ /dev/null
-fn demo_mut_advanced_unique(our: &mut i32) -> i32 {
- unknown_code_1(&*our);
-
- // This "re-asserts" uniqueness of the reference: After writing, we know
- // our tag is at the top of the stack.
- *our = 5;
-
- unknown_code_2();
-
- // We know this will return 5
- *our
-}
-
-// Now comes the evil context
-use std::ptr;
-
-static mut LEAK: *mut i32 = ptr::null_mut();
-
-fn unknown_code_1(x: &i32) { unsafe {
- LEAK = x as *const _ as *mut _;
-} }
-
-fn unknown_code_2() { unsafe {
- *LEAK = 7; //~ ERROR does not exist on the stack
-} }
-
-fn main() {
- assert_eq!(demo_mut_advanced_unique(&mut 0), 5);
-}
+++ /dev/null
-fn main() {
- let mut x = 0;
- let y: *const i32 = &x;
- x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local
-
- assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack
-
- assert_eq!(x, 1);
-}
+++ /dev/null
-// Make sure that we cannot pass by argument a `&mut` that got already invalidated.
-fn foo(_: &mut i32) {}
-
-fn main() {
- let x = &mut 42;
- let xraw = x as *mut _;
- let xref = unsafe { &mut *xraw };
- let _val = unsafe { *xraw }; // invalidate xref
- foo(xref); //~ ERROR does not exist on the stack
-}
+++ /dev/null
-// Make sure that we cannot pass by argument a `&` that got already invalidated.
-fn foo(_: &i32) {}
-
-fn main() {
- let x = &mut 42;
- let xraw = &*x as *const _ as *mut _;
- let xref = unsafe { &*xraw };
- unsafe { *xraw = 42 }; // unfreeze
- foo(xref); //~ ERROR is not frozen
-}
+++ /dev/null
-#![allow(unused_variables)]
-
-static mut PTR: *mut u8 = 0 as *mut _;
-
-fn fun1(x: &mut u8) {
- unsafe {
- PTR = x;
- }
-}
-
-fn fun2() {
- // Now we use a pointer we are not allowed to use
- let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack
-}
-
-fn main() {
- let val = &mut 0; // FIXME: This should also work with a local variable, but currently it does not.
- fun1(val);
- *val = 2; // this invalidates any raw ptrs `fun1` might have created.
- fun2(); // if they now use a raw ptr they break our reference
-}
+++ /dev/null
-// Make sure that we cannot return a `&mut` that got already invalidated.
-fn foo(x: &mut (i32, i32)) -> &mut i32 {
- let xraw = x as *mut (i32, i32);
- let ret = unsafe { &mut (*xraw).1 };
- let _val = unsafe { *xraw }; // invalidate xref
- ret //~ ERROR does not exist on the stack
-}
-
-fn main() {
- foo(&mut (1, 2));
-}
+++ /dev/null
-// Make sure that we cannot return a `&` that got already invalidated.
-fn foo(x: &mut (i32, i32)) -> &i32 {
- let xraw = x as *mut (i32, i32);
- let ret = unsafe { &(*xraw).1 };
- unsafe { *xraw = (42, 23) }; // unfreeze
- ret //~ ERROR is not frozen
-}
-
-fn main() {
- foo(&mut (1, 2));
-}
+++ /dev/null
-// FIXME still considering whether we are okay with this not being an error
-// ignore-test
-
-static X: usize = 5;
-
-#[allow(mutable_transmutes)]
-fn main() {
- let _x = unsafe {
- std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR mutable reference with frozen tag
- };
-}
+++ /dev/null
-// Make sure we cannot use raw ptrs that got transmuted from mutable references
-// (i.e, no EscapeToRaw happened).
-// We could, in principle, to EscapeToRaw lazily to allow this code, but that
-// would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in
-// `run-pass/stacked-borrows.rs`), and thus increase overall complexity.
-use std::mem;
-
-fn main() {
- let mut x: i32 = 42;
- let raw: *mut i32 = unsafe { mem::transmute(&mut x) };
- unsafe { *raw = 13; } //~ ERROR does not exist on the stack
-}
+++ /dev/null
-// Make sure we cannot use raw ptrs to access a local that
-// we took the direct address of.
-fn main() {
- let mut x = 42;
- let raw = &mut x as *mut i32 as usize as *mut i32;
- let _ptr = &mut x;
- unsafe { *raw = 13; } //~ ERROR does not exist on the stack
-}
+++ /dev/null
-#![feature(core_intrinsics)]
-
-use std::mem;
-
-fn main() {
- let x: Option<Box<[u8]>> = unsafe {
- let z = std::intrinsics::add_with_overflow(0usize, 0usize);
- std::mem::transmute::<(usize, bool), Option<Box<[u8]>>>(z)
- };
- let y = &x;
- // Now read this bytewise. There should be (ptr_size+1) def bytes followed by (ptr_size-1) undef bytes (the padding after the bool) in there.
- let z : *const u8 = y as *const _ as *const _;
- let first_undef = mem::size_of::<usize>() as isize + 1;
- for i in 0..first_undef {
- let byte = unsafe { *z.offset(i) };
- assert_eq!(byte, 0);
- }
- let v = unsafe { *z.offset(first_undef) };
- if v == 0 {} //~ ERROR attempted to read undefined bytes
-}
// whitelist.
flags.push("-Zmir-opt-level=1".to_owned());
}
+ if !have_fullmir() {
+ // Validation relies on the EscapeToRaw statements being emitted
+ flags.push("-Zmiri-disable-validation".to_owned());
+ }
let mut config = mk_config("ui");
config.src_base = PathBuf::from(path);