-// compile-flags: -Zmiri-allow-ptr-int-transmute
// 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!
-#![feature(untagged_unions)]
-
use std::mem;
+union HiddenRef {
+ // We avoid retagging at this type, so shared vs mutable does not matter.
+ r: &'static i32,
+}
+
fn main() {
let mut x: i32 = 15;
let xref1 = &mut x;
- let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) };
+ let xref1_sneaky: HiddenRef = unsafe { mem::transmute_copy(&xref1) };
// Derived from `xref1`, so using raw value is still ok, ...
let xref2 = &mut *xref1;
callee(xref1_sneaky);
//~^ ERROR: borrow 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 };
+fn callee(xref1: HiddenRef) {
// Doing the deref and the transmute (through the union) in the same place expression
// should avoid retagging.
- let _val = unsafe { *xref1.to };
+ let _val = unsafe { *xref1.r };
}
help: <TAG> was later invalidated at offsets [0x0..0x4]
--> $DIR/illegal_read3.rs:LL:CC
|
-LL | let _val = unsafe { *xref1.to };
- | ^^^^^^^^^
+LL | let _val = unsafe { *xref1.r };
+ | ^^^^^^^^
= note: inside `main` at $DIR/illegal_read3.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-// compile-flags: -Zmiri-allow-uninit-numbers
#![feature(core_intrinsics)]
use std::mem;
assert_eq!(byte, 0);
}
let v = unsafe { *z.offset(first_undef) };
+ //~^ ERROR uninitialized
if v == 0 { println!("it is zero"); }
- //~^ ERROR this operation requires initialized memory
}
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes
--> $DIR/transmute-pair-uninit.rs:LL:CC
|
-LL | if v == 0 { println!("it is zero"); }
- | ^^^^^^ using uninitialized data, but this operation requires initialized memory
+LL | let v = unsafe { *z.offset(first_undef) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-// compile-flags: -Zmiri-allow-uninit-numbers
fn main() {
let v: Vec<u8> = Vec::with_capacity(10);
- let undef = unsafe { *v.get_unchecked(5) };
- let x = undef + 1; //~ ERROR this operation requires initialized memory
+ let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized
+ let x = undef + 1;
panic!("this should never print: {}", x);
}
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes
--> $DIR/uninit_byte_read.rs:LL:CC
|
-LL | let x = undef + 1;
- | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+LL | let undef = unsafe { *v.get_unchecked(5) };
+ | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+// Even when uninit numbers are allowed, this enum is not.
// compile-flags: -Zmiri-allow-uninit-numbers
#![allow(unused, deprecated, invalid_value)]
-// compile-flags: -Zmiri-allow-ptr-int-transmute
-
-// This returns a miri pointer at type usize, if the argument is a proper pointer
+// This strips provenance
fn transmute_ptr_to_int<T>(x: *const T) -> usize {
unsafe { std::mem::transmute(x) }
}
// transmuting.
let a: *const i32 = &42;
let b = transmute_ptr_to_int(a) as u8;
- let c = a as usize as u8;
+ let c = a as u8;
assert_eq!(b, c);
}
// Stacked Borrows disallows this becuase the reference is never cast to a raw pointer.
-// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute
+// compile-flags: -Zmiri-disable-stacked-borrows
fn main() {
// If we are careful, we can exploit data layout...
let raw = unsafe {
- std::mem::transmute::<&[u8], [usize; 2]>(&[42])
+ std::mem::transmute::<&[u8], [*const u8; 2]>(&[42])
};
- let ptr = raw[0] + raw[1];
- // We transmute both ways, to really test allow-ptr-int-transmute.
- let ptr: *const u8 = unsafe { std::mem::transmute(ptr) };
- // The pointer is one-past-the end, but we decrement it into bounds before using it
- assert_eq!(unsafe { *ptr.offset(-1) }, 42);
+ let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) };
+ assert_eq!(unsafe { *ptr }, 42);
}