Skip to content

Commit ae3adae

Browse files
committed
TB: add missing interior_mutability test file
1 parent f456b40 commit ae3adae

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//@revisions: default uniq
2+
//@compile-flags: -Zmiri-tree-borrows
3+
//@[uniq]compile-flags: -Zmiri-unique-is-unique
4+
use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
5+
use std::mem::{self, MaybeUninit};
6+
7+
fn main() {
8+
aliasing_mut_and_shr();
9+
aliasing_frz_and_shr();
10+
into_interior_mutability();
11+
unsafe_cell_2phase();
12+
unsafe_cell_deallocate();
13+
unsafe_cell_invalidate();
14+
refcell_basic();
15+
ref_protector();
16+
ref_mut_protector();
17+
rust_issue_68303();
18+
}
19+
20+
fn aliasing_mut_and_shr() {
21+
fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
22+
*aliasing += 4;
23+
let _escape_to_raw = rc as *const _;
24+
*aliasing += 4;
25+
let _shr = &*rc;
26+
*aliasing += 4;
27+
// also turning this into a frozen ref now must work
28+
let aliasing = &*aliasing;
29+
let _val = *aliasing;
30+
let _escape_to_raw = rc as *const _; // this must NOT unfreeze
31+
let _val = *aliasing;
32+
let _shr = &*rc; // this must NOT unfreeze
33+
let _val = *aliasing;
34+
}
35+
36+
let rc = RefCell::new(23);
37+
let mut bmut = rc.borrow_mut();
38+
inner(&rc, &mut *bmut);
39+
drop(bmut);
40+
assert_eq!(*rc.borrow(), 23 + 12);
41+
}
42+
43+
fn aliasing_frz_and_shr() {
44+
fn inner(rc: &RefCell<i32>, aliasing: &i32) {
45+
let _val = *aliasing;
46+
let _escape_to_raw = rc as *const _; // this must NOT unfreeze
47+
let _val = *aliasing;
48+
let _shr = &*rc; // this must NOT unfreeze
49+
let _val = *aliasing;
50+
}
51+
52+
let rc = RefCell::new(23);
53+
let bshr = rc.borrow();
54+
inner(&rc, &*bshr);
55+
assert_eq!(*rc.borrow(), 23);
56+
}
57+
58+
// Getting a pointer into a union with interior mutability used to be tricky
59+
// business (https://github.com/rust-lang/miri/issues/615), but it should work
60+
// now.
61+
fn into_interior_mutability() {
62+
let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
63+
x.as_ptr();
64+
x.write((Cell::new(0), 1));
65+
let ptr = unsafe { x.assume_init_ref() };
66+
assert_eq!(ptr.1, 1);
67+
}
68+
69+
// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
70+
// invalidate aliases.
71+
fn unsafe_cell_2phase() {
72+
unsafe {
73+
let x = &UnsafeCell::new(vec![]);
74+
let x2 = &*x;
75+
(*x.get()).push(0);
76+
let _val = (*x2.get()).get(0);
77+
}
78+
}
79+
80+
/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call.
81+
/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.)
82+
fn unsafe_cell_deallocate() {
83+
fn f(x: &UnsafeCell<i32>) {
84+
let b: Box<i32> = unsafe { Box::from_raw(x as *const _ as *mut i32) };
85+
drop(b)
86+
}
87+
88+
let b = Box::new(0i32);
89+
f(unsafe { mem::transmute(Box::into_raw(b)) });
90+
}
91+
92+
/// As a side-effect of the above, we also allow this -- at least for now.
93+
fn unsafe_cell_invalidate() {
94+
fn f(_x: &UnsafeCell<i32>, y: *mut i32) {
95+
// Writing to y invalidates x, but that is okay.
96+
unsafe {
97+
*y += 1;
98+
}
99+
}
100+
101+
let mut x = 0i32;
102+
let raw1 = &mut x as *mut _;
103+
let ref1 = unsafe { &mut *raw1 };
104+
let raw2 = ref1 as *mut _;
105+
// Now the borrow stack is: raw1, ref2, raw2.
106+
// So using raw1 invalidates raw2.
107+
f(unsafe { mem::transmute(raw2) }, raw1);
108+
}
109+
110+
fn refcell_basic() {
111+
let c = RefCell::new(42);
112+
{
113+
let s1 = c.borrow();
114+
let _x: i32 = *s1;
115+
let s2 = c.borrow();
116+
let _x: i32 = *s1;
117+
let _y: i32 = *s2;
118+
let _x: i32 = *s1;
119+
let _y: i32 = *s2;
120+
}
121+
{
122+
let mut m = c.borrow_mut();
123+
let _z: i32 = *m;
124+
{
125+
let s: &i32 = &*m;
126+
let _x = *s;
127+
}
128+
*m = 23;
129+
let _z: i32 = *m;
130+
}
131+
{
132+
let s1 = c.borrow();
133+
let _x: i32 = *s1;
134+
let s2 = c.borrow();
135+
let _x: i32 = *s1;
136+
let _y: i32 = *s2;
137+
let _x: i32 = *s1;
138+
let _y: i32 = *s2;
139+
}
140+
}
141+
142+
// Adding a Stacked Borrows protector for `Ref` would break this
143+
fn ref_protector() {
144+
fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
145+
// `r` has a shared reference, it is passed in as argument and hence
146+
// a protector is added that marks this memory as read-only for the entire
147+
// duration of this function.
148+
drop(r);
149+
// *oops* here we can mutate that memory.
150+
*rc.borrow_mut() = 2;
151+
}
152+
153+
let rc = RefCell::new(0);
154+
break_it(&rc, rc.borrow())
155+
}
156+
157+
fn ref_mut_protector() {
158+
fn break_it(rc: &RefCell<i32>, r: RefMut<'_, i32>) {
159+
// `r` has a shared reference, it is passed in as argument and hence
160+
// a protector is added that marks this memory as inaccessible for the entire
161+
// duration of this function
162+
drop(r);
163+
// *oops* here we can mutate that memory.
164+
*rc.borrow_mut() = 2;
165+
}
166+
167+
let rc = RefCell::new(0);
168+
break_it(&rc, rc.borrow_mut())
169+
}
170+
171+
/// Make sure we do not have bad enum layout optimizations.
172+
fn rust_issue_68303() {
173+
let optional = Some(RefCell::new(false));
174+
let mut handle = optional.as_ref().unwrap().borrow_mut();
175+
assert!(optional.is_some());
176+
*handle = true;
177+
}

0 commit comments

Comments
 (0)