blob: 83e1d9c70ed508992eaae9dd398cfac96b45ad72 [file] [log] [blame]
// 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<T>(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<u8>);
name!(x as *mut _, "x");
let y = &mut *base as *mut UnsafeCell<u8> 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<u64> 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<u64>);
name!(x as *mut _, "x");
let y = &mut *base as *mut UnsafeCell<u64> 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);
}