// We disable the GC for this test because it would change what is printed. //@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 #[path = "../../utils/mod.rs"] #[macro_use] mod utils; use std::cell::UnsafeCell; // We exhaustively check that Reserved behaves as we want under all of the // following conditions: // - with or without interior mutability // - with or without a protector // - for a foreign read or write // Of these cases, those in this file are the ones that must not cause // immediate UB, and those that do are in tests/fail/tree-borrows/reserved/ // and are the combinations [_ + protected + write] fn main() { unsafe { cell_protected_read(); cell_unprotected_read(); cell_unprotected_write(); int_protected_read(); int_unprotected_read(); int_unprotected_write(); } } fn print(msg: &str) { eprintln!("{msg}"); } unsafe fn read_second(x: &mut T, y: *mut u8) { name!(x as *mut T as *mut u8=>1, "caller:x"); name!(x as *mut T as *mut u8, "callee:x"); name!(y, "caller:y"); name!(y, "callee:y"); let _val = *y; } // Foreign Read on a interior mutable Protected Reserved turns it Frozen. unsafe fn cell_protected_read() { print("[interior mut + protected] Foreign Read: Re* -> Frz"); let base = &mut UnsafeCell::new(0u8); name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell); name!(x as *mut _, "x"); let y = &mut *base as *mut UnsafeCell as *mut u8; name!(y); read_second(x, y); // Foreign Read for callee:x print_state!(alloc_id); } // Foreign Read on an interior mutable pointer is a noop. unsafe fn cell_unprotected_read() { print("[interior mut] Foreign Read: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell<_>); name!(x as *mut _, "x"); let y = &mut *base as *mut UnsafeCell as *mut u64; name!(y); let _val = *y; // Foreign Read for x print_state!(alloc_id); } // Foreign Write on an interior mutable pointer is a noop. // Also y must become Unique. unsafe fn cell_unprotected_write() { print("[interior mut] Foreign Write: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell); name!(x as *mut _, "x"); let y = &mut *base as *mut UnsafeCell as *mut u64; name!(y); *y = 1; // Foreign Write for x print_state!(alloc_id); } // Foreign Read on a Protected Reserved turns it Frozen. unsafe fn int_protected_read() { print("[protected] Foreign Read: Res -> Frz"); let base = &mut 0u8; let alloc_id = alloc_id!(base); name!(base); let x = &mut *(base as *mut u8); name!(x); let y = (&mut *base) as *mut u8; name!(y); read_second(x, y); // Foreign Read for callee:x print_state!(alloc_id); } // Foreign Read on a Reserved is a noop. // Also y must become Unique. unsafe fn int_unprotected_read() { print("[] Foreign Read: Res -> Res"); let base = &mut 0u8; name!(base); let alloc_id = alloc_id!(base); let x = &mut *(base as *mut u8); name!(x); let y = (&mut *base) as *mut u8; name!(y); let _val = *y; // Foreign Read for x print_state!(alloc_id); } // Foreign Write on a Reserved turns it Disabled. unsafe fn int_unprotected_write() { print("[] Foreign Write: Res -> Dis"); let base = &mut 0u8; name!(base); let alloc_id = alloc_id!(base); let x = &mut *(base as *mut u8); name!(x); let y = (&mut *base) as *mut u8; name!(y); *y = 1; // Foreign Write for x print_state!(alloc_id); }