]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
make &mut !Unpin not dereferenceable
[rust.git] / src / tools / miri / tests / pass / stacked-borrows / stacked-borrows.rs
1 //@compile-flags: -Zmiri-retag-fields
2 #![feature(allocator_api)]
3 use std::ptr;
4
5 // Test various stacked-borrows-related things.
6 fn main() {
7     read_does_not_invalidate1();
8     read_does_not_invalidate2();
9     mut_raw_then_mut_shr();
10     mut_shr_then_mut_raw();
11     mut_raw_mut();
12     partially_invalidate_mut();
13     drop_after_sharing();
14     direct_mut_to_const_raw();
15     two_raw();
16     shr_and_raw();
17     disjoint_mutable_subborrows();
18     raw_ref_to_part();
19     array_casts();
20     mut_below_shr();
21     wide_raw_ptr_in_tuple();
22     not_unpin_not_protected();
23 }
24
25 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
26 // NOT invalidate other reborrows.
27 fn read_does_not_invalidate1() {
28     fn foo(x: &mut (i32, i32)) -> &i32 {
29         let xraw = x as *mut (i32, i32);
30         let ret = unsafe { &(*xraw).1 };
31         let _val = x.1; // we just read, this does NOT invalidate the reborrows.
32         ret
33     }
34     assert_eq!(*foo(&mut (1, 2)), 2);
35 }
36 // Same as above, but this time we first create a raw, then read from `&mut`
37 // and then freeze from the raw.
38 fn read_does_not_invalidate2() {
39     fn foo(x: &mut (i32, i32)) -> &i32 {
40         let xraw = x as *mut (i32, i32);
41         let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
42         let ret = unsafe { &(*xraw).1 };
43         ret
44     }
45     assert_eq!(*foo(&mut (1, 2)), 2);
46 }
47
48 // Escape a mut to raw, then share the same mut and use the share, then the raw.
49 // That should work.
50 fn mut_raw_then_mut_shr() {
51     let mut x = 2;
52     let xref = &mut x;
53     let xraw = &mut *xref as *mut _;
54     let xshr = &*xref;
55     assert_eq!(*xshr, 2);
56     unsafe {
57         *xraw = 4;
58     }
59     assert_eq!(x, 4);
60 }
61
62 // Create first a shared reference and then a raw pointer from a `&mut`
63 // should permit mutation through that raw pointer.
64 fn mut_shr_then_mut_raw() {
65     let xref = &mut 2;
66     let _xshr = &*xref;
67     let xraw = xref as *mut _;
68     unsafe {
69         *xraw = 3;
70     }
71     assert_eq!(*xref, 3);
72 }
73
74 // Ensure that if we derive from a mut a raw, and then from that a mut,
75 // and then read through the original mut, that does not invalidate the raw.
76 // This shows that the read-exception for `&mut` applies even if the `Shr` item
77 // on the stack is not at the top.
78 fn mut_raw_mut() {
79     let mut x = 2;
80     {
81         let xref1 = &mut x;
82         let xraw = xref1 as *mut _;
83         let _xref2 = unsafe { &mut *xraw };
84         let _val = *xref1;
85         unsafe {
86             *xraw = 4;
87         }
88         // we can now use both xraw and xref1, for reading
89         assert_eq!(*xref1, 4);
90         assert_eq!(unsafe { *xraw }, 4);
91         assert_eq!(*xref1, 4);
92         assert_eq!(unsafe { *xraw }, 4);
93         // we cannot use xref2; see `compile-fail/stacked-borows/illegal_read4.rs`
94     }
95     assert_eq!(x, 4);
96 }
97
98 fn partially_invalidate_mut() {
99     let data = &mut (0u8, 0u8);
100     let reborrow = &mut *data as *mut (u8, u8);
101     let shard = unsafe { &mut (*reborrow).0 };
102     data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
103     *shard += 1; // so we can still use `shard`.
104     assert_eq!(*data, (1, 1));
105 }
106
107 // Make sure that we can handle the situation where a loaction is frozen when being dropped.
108 fn drop_after_sharing() {
109     let x = String::from("hello!");
110     let _len = x.len();
111 }
112
113 // Make sure that coercing &mut T to *const T produces a writeable pointer.
114 fn direct_mut_to_const_raw() {
115     // TODO: This is currently disabled, waiting on a decision on <https://github.com/rust-lang/rust/issues/56604>
116     /*let x = &mut 0;
117     let y: *const i32 = x;
118     unsafe { *(y as *mut i32) = 1; }
119     assert_eq!(*x, 1);
120     */
121 }
122
123 // Make sure that we can create two raw pointers from a mutable reference and use them both.
124 fn two_raw() {
125     unsafe {
126         let x = &mut 0;
127         let y1 = x as *mut _;
128         let y2 = x as *mut _;
129         *y1 += 2;
130         *y2 += 1;
131     }
132 }
133
134 // Make sure that creating a *mut does not invalidate existing shared references.
135 fn shr_and_raw() {
136     unsafe {
137         use std::mem;
138         let x = &mut 0;
139         let y1: &i32 = mem::transmute(&*x); // launder lifetimes
140         let y2 = x as *mut _;
141         let _val = *y1;
142         *y2 += 1;
143     }
144 }
145
146 fn disjoint_mutable_subborrows() {
147     struct Foo {
148         a: String,
149         b: Vec<u32>,
150     }
151
152     unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String {
153         &mut (*this).a
154     }
155
156     unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec<u32> {
157         &mut (*this).b
158     }
159
160     let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] };
161
162     let ptr = &mut foo as *mut Foo;
163
164     let a = unsafe { borrow_field_a(ptr) };
165     let b = unsafe { borrow_field_b(ptr) };
166     b.push(4);
167     a.push_str(" world");
168     eprintln!("{:?} {:?}", a, b);
169 }
170
171 fn raw_ref_to_part() {
172     struct Part {
173         _lame: i32,
174     }
175
176     #[repr(C)]
177     struct Whole {
178         part: Part,
179         extra: i32,
180     }
181
182     let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
183     let whole = ptr::addr_of_mut!(*Box::leak(it));
184     let part = unsafe { ptr::addr_of_mut!((*whole).part) };
185     let typed = unsafe { &mut *(part as *mut Whole) };
186     assert!(typed.extra == 42);
187     drop(unsafe { Box::from_raw(whole) });
188 }
189
190 /// When casting an array reference to a raw element ptr, that should cover the whole array.
191 fn array_casts() {
192     let mut x: [usize; 2] = [0, 0];
193     let p = &mut x as *mut usize;
194     unsafe {
195         *p.add(1) = 1;
196     }
197
198     let x: [usize; 2] = [0, 1];
199     let p = &x as *const usize;
200     assert_eq!(unsafe { *p.add(1) }, 1);
201 }
202
203 /// Transmuting &&i32 to &&mut i32 is fine.
204 fn mut_below_shr() {
205     let x = 0;
206     let y = &x;
207     let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) };
208     let r = &**p;
209     let _val = *r;
210 }
211
212 fn wide_raw_ptr_in_tuple() {
213     let mut x: Box<dyn std::any::Any> = Box::new("ouch");
214     let r = &mut *x as *mut dyn std::any::Any;
215     // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw
216     // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and
217     // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong.
218     let pair = (r, &0);
219     let r = unsafe { &mut *pair.0 };
220     // Make sure the fn ptr part of the vtable is still fine.
221     r.type_id();
222 }
223
224 fn not_unpin_not_protected() {
225     // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
226     // don't add protectors. (We could, but until we have a better idea for where we want to go with
227     // the self-referntial-generator situation, it does not seem worth the potential trouble.)
228     use std::marker::PhantomPinned;
229
230     pub struct NotUnpin(i32, PhantomPinned);
231
232     fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
233         // `f` may mutate, but it may not deallocate!
234         f(x)
235     }
236
237     inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
238         let raw = x as *mut _;
239         drop(unsafe { Box::from_raw(raw) });
240     });
241 }