//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; // Just to make sure that casting a ref to raw, to int and back to raw // and only then using it works. This rules out ideas like "do escape-to-raw lazily"; // after casting to int and back, we lost the tag that could have let us do that. fn ref_raw_int_raw() { let mut x = 3; let xref = &mut x; let xraw = xref as *mut i32 as usize as *mut i32; assert_eq!(unsafe { *xraw }, 3); } /// Ensure that we do not just pick the topmost possible item on int2ptr casts. fn example(variant: bool) { unsafe { fn not_so_innocent(x: &mut u32) -> usize { let x_raw4 = x as *mut u32; x_raw4.expose_addr() } let mut c = 42u32; let x_unique1 = &mut c; // [..., Unique(1)] let x_raw2 = x_unique1 as *mut u32; let x_raw2_addr = x_raw2.expose_addr(); // [..., Unique(1), SharedRW(2)] let x_unique3 = &mut *x_raw2; // [.., Unique(1), SharedRW(2), Unique(3)] assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). // And indeed if `variant == true` it is the only possible choice. // But if `variant == false` then 2 is the only possible choice! let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); if variant { // If we picked 2, this will invalidate 3. *x_wildcard = 10; // Now we use 3. Only possible if above we picked 4. *x_unique3 = 12; } else { // This invalidates tag 4. *x_unique3 = 10; // Now try to write with the "guessed" tag; it must be 2. *x_wildcard = 12; } } } fn test() { unsafe { let root = &mut 42; let root_raw = root as *mut i32; let addr1 = root_raw as usize; let child = &mut *root_raw; let child_raw = child as *mut i32; let addr2 = child_raw as usize; assert_eq!(addr1, addr2); // First use child. *(addr2 as *mut i32) -= 2; // picks child_raw *child -= 2; // Then use root. *(addr1 as *mut i32) += 2; // picks root_raw *root += 2; // Value should be unchanged. assert_eq!(*root, 42); } } fn main() { ref_raw_int_raw(); example(false); example(true); test(); }