1 //@compile-flags: -Zmiri-retag-fields
2 use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
3 use std::mem::{self, MaybeUninit};
6 aliasing_mut_and_shr();
7 aliasing_frz_and_shr();
8 into_interior_mutability();
10 unsafe_cell_deallocate();
11 unsafe_cell_invalidate();
18 fn aliasing_mut_and_shr() {
19 fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
21 let _escape_to_raw = rc as *const _;
25 // also turning this into a frozen ref now must work
26 let aliasing = &*aliasing;
28 let _escape_to_raw = rc as *const _; // this must NOT unfreeze
30 let _shr = &*rc; // this must NOT unfreeze
34 let rc = RefCell::new(23);
35 let mut bmut = rc.borrow_mut();
36 inner(&rc, &mut *bmut);
38 assert_eq!(*rc.borrow(), 23 + 12);
41 fn aliasing_frz_and_shr() {
42 fn inner(rc: &RefCell<i32>, aliasing: &i32) {
44 let _escape_to_raw = rc as *const _; // this must NOT unfreeze
46 let _shr = &*rc; // this must NOT unfreeze
50 let rc = RefCell::new(23);
51 let bshr = rc.borrow();
53 assert_eq!(*rc.borrow(), 23);
56 // Getting a pointer into a union with interior mutability used to be tricky
57 // business (https://github.com/rust-lang/miri/issues/615), but it should work
59 fn into_interior_mutability() {
60 let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
62 x.write((Cell::new(0), 1));
63 let ptr = unsafe { x.assume_init_ref() };
67 // Two-phase borrows of the pointer returned by UnsafeCell::get() should not
68 // invalidate aliases.
69 fn unsafe_cell_2phase() {
71 let x = &UnsafeCell::new(vec![]);
74 let _val = (*x2.get()).get(0);
78 /// Make sure we can deallocate an UnsafeCell that was passed to an active fn call.
79 /// (This is the fix for https://github.com/rust-lang/rust/issues/55005.)
80 fn unsafe_cell_deallocate() {
81 fn f(x: &UnsafeCell<i32>) {
82 let b: Box<i32> = unsafe { Box::from_raw(x as *const _ as *mut i32) };
86 let b = Box::new(0i32);
87 f(unsafe { mem::transmute(Box::into_raw(b)) });
90 /// As a side-effect of the above, we also allow this -- at least for now.
91 fn unsafe_cell_invalidate() {
92 fn f(_x: &UnsafeCell<i32>, y: *mut i32) {
93 // Writing to y invalidates x, but that is okay.
100 let raw1 = &mut x as *mut _;
101 let ref1 = unsafe { &mut *raw1 };
102 let raw2 = ref1 as *mut _;
103 // Now the borrow stack is: raw1, ref2, raw2.
104 // So using raw1 invalidates raw2.
105 f(unsafe { mem::transmute(raw2) }, raw1);
109 let c = RefCell::new(42);
120 let mut m = c.borrow_mut();
140 // Adding a Stacked Borrows protector for `Ref` would break this
142 fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
143 // `r` has a shared reference, it is passed in as argument and hence
144 // a protector is added that marks this memory as read-only for the entire
145 // duration of this function.
147 // *oops* here we can mutate that memory.
148 *rc.borrow_mut() = 2;
151 let rc = RefCell::new(0);
152 break_it(&rc, rc.borrow())
155 fn ref_mut_protector() {
156 fn break_it(rc: &RefCell<i32>, r: RefMut<'_, i32>) {
157 // `r` has a shared reference, it is passed in as argument and hence
158 // a protector is added that marks this memory as inaccessible for the entire
159 // duration of this function
161 // *oops* here we can mutate that memory.
162 *rc.borrow_mut() = 2;
165 let rc = RefCell::new(0);
166 break_it(&rc, rc.borrow_mut())
169 /// Make sure we do not have bad enum layout optimizations.
170 fn rust_issue_68303() {
171 let optional = Some(RefCell::new(false));
172 let mut handle = optional.as_ref().unwrap().borrow_mut();
173 assert!(optional.is_some());