]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
Rollup merge of #105784 - yanns:update_stdarch, r=Amanieu
[rust.git] / src / tools / miri / tests / pass / stacked-borrows / interior_mutability.rs
1 //@compile-flags: -Zmiri-retag-fields
2 use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
3 use std::mem::{self, MaybeUninit};
4
5 fn main() {
6     aliasing_mut_and_shr();
7     aliasing_frz_and_shr();
8     into_interior_mutability();
9     unsafe_cell_2phase();
10     unsafe_cell_deallocate();
11     unsafe_cell_invalidate();
12     refcell_basic();
13     ref_protector();
14     ref_mut_protector();
15     rust_issue_68303();
16 }
17
18 fn aliasing_mut_and_shr() {
19     fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
20         *aliasing += 4;
21         let _escape_to_raw = rc as *const _;
22         *aliasing += 4;
23         let _shr = &*rc;
24         *aliasing += 4;
25         // also turning this into a frozen ref now must work
26         let aliasing = &*aliasing;
27         let _val = *aliasing;
28         let _escape_to_raw = rc as *const _; // this must NOT unfreeze
29         let _val = *aliasing;
30         let _shr = &*rc; // this must NOT unfreeze
31         let _val = *aliasing;
32     }
33
34     let rc = RefCell::new(23);
35     let mut bmut = rc.borrow_mut();
36     inner(&rc, &mut *bmut);
37     drop(bmut);
38     assert_eq!(*rc.borrow(), 23 + 12);
39 }
40
41 fn aliasing_frz_and_shr() {
42     fn inner(rc: &RefCell<i32>, aliasing: &i32) {
43         let _val = *aliasing;
44         let _escape_to_raw = rc as *const _; // this must NOT unfreeze
45         let _val = *aliasing;
46         let _shr = &*rc; // this must NOT unfreeze
47         let _val = *aliasing;
48     }
49
50     let rc = RefCell::new(23);
51     let bshr = rc.borrow();
52     inner(&rc, &*bshr);
53     assert_eq!(*rc.borrow(), 23);
54 }
55
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
58 // now.
59 fn into_interior_mutability() {
60     let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
61     x.as_ptr();
62     x.write((Cell::new(0), 1));
63     let ptr = unsafe { x.assume_init_ref() };
64     assert_eq!(ptr.1, 1);
65 }
66
67 // Two-phase borrows of the pointer returned by UnsafeCell::get() should not
68 // invalidate aliases.
69 fn unsafe_cell_2phase() {
70     unsafe {
71         let x = &UnsafeCell::new(vec![]);
72         let x2 = &*x;
73         (*x.get()).push(0);
74         let _val = (*x2.get()).get(0);
75     }
76 }
77
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) };
83         drop(b)
84     }
85
86     let b = Box::new(0i32);
87     f(unsafe { mem::transmute(Box::into_raw(b)) });
88 }
89
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.
94         unsafe {
95             *y += 1;
96         }
97     }
98
99     let mut x = 0i32;
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);
106 }
107
108 fn refcell_basic() {
109     let c = RefCell::new(42);
110     {
111         let s1 = c.borrow();
112         let _x: i32 = *s1;
113         let s2 = c.borrow();
114         let _x: i32 = *s1;
115         let _y: i32 = *s2;
116         let _x: i32 = *s1;
117         let _y: i32 = *s2;
118     }
119     {
120         let mut m = c.borrow_mut();
121         let _z: i32 = *m;
122         {
123             let s: &i32 = &*m;
124             let _x = *s;
125         }
126         *m = 23;
127         let _z: i32 = *m;
128     }
129     {
130         let s1 = c.borrow();
131         let _x: i32 = *s1;
132         let s2 = c.borrow();
133         let _x: i32 = *s1;
134         let _y: i32 = *s2;
135         let _x: i32 = *s1;
136         let _y: i32 = *s2;
137     }
138 }
139
140 // Adding a Stacked Borrows protector for `Ref` would break this
141 fn ref_protector() {
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.
146         drop(r);
147         // *oops* here we can mutate that memory.
148         *rc.borrow_mut() = 2;
149     }
150
151     let rc = RefCell::new(0);
152     break_it(&rc, rc.borrow())
153 }
154
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
160         drop(r);
161         // *oops* here we can mutate that memory.
162         *rc.borrow_mut() = 2;
163     }
164
165     let rc = RefCell::new(0);
166     break_it(&rc, rc.borrow_mut())
167 }
168
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());
174     *handle = true;
175 }