]> git.lizzy.rs Git - rust.git/blob - tests/run-pass/stacked-borrows/stacked-borrows.rs
Stacked Borrows: test raw-ref-to-field with raw ptr tracking
[rust.git] / tests / run-pass / stacked-borrows / stacked-borrows.rs
1 // compile-flags: -Zmiri-track-raw-pointers
2 // ignore-windows (FIXME: tracking raw pointers does not work on Windows)
3 #![feature(raw_ref_macros)]
4 use std::ptr;
5     
6 // Test various stacked-borrows-related things.
7 fn main() {
8     read_does_not_invalidate1();
9     read_does_not_invalidate2();
10     mut_raw_then_mut_shr();
11     mut_shr_then_mut_raw();
12     mut_raw_mut();
13     partially_invalidate_mut();
14     drop_after_sharing();
15     direct_mut_to_const_raw();
16     two_raw();
17     shr_and_raw();
18     disjoint_mutable_subborrows();
19     raw_ref_to_part();
20 }
21
22 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
23 // NOT invalidate other reborrows.
24 fn read_does_not_invalidate1() {
25     fn foo(x: &mut (i32, i32)) -> &i32 {
26         let xraw = x as *mut (i32, i32);
27         let ret = unsafe { &(*xraw).1 };
28         let _val = x.1; // we just read, this does NOT invalidate the reborrows.
29         ret
30     }
31     assert_eq!(*foo(&mut (1, 2)), 2);
32 }
33 // Same as above, but this time we first create a raw, then read from `&mut`
34 // and then freeze from the raw.
35 fn read_does_not_invalidate2() {
36     fn foo(x: &mut (i32, i32)) -> &i32 {
37         let xraw = x as *mut (i32, i32);
38         let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
39         let ret = unsafe { &(*xraw).1 };
40         ret
41     }
42     assert_eq!(*foo(&mut (1, 2)), 2);
43 }
44
45 // Escape a mut to raw, then share the same mut and use the share, then the raw.
46 // That should work.
47 fn mut_raw_then_mut_shr() {
48     let mut x = 2;
49     let xref = &mut x;
50     let xraw = &mut *xref as *mut _;
51     let xshr = &*xref;
52     assert_eq!(*xshr, 2);
53     unsafe { *xraw = 4; }
54     assert_eq!(x, 4);
55 }
56
57 // Create first a shared reference and then a raw pointer from a `&mut`
58 // should permit mutation through that raw pointer.
59 fn mut_shr_then_mut_raw() {
60     let xref = &mut 2;
61     let _xshr = &*xref;
62     let xraw = xref as *mut _;
63     unsafe { *xraw = 3; }
64     assert_eq!(*xref, 3);
65 }
66
67 // Ensure that if we derive from a mut a raw, and then from that a mut,
68 // and then read through the original mut, that does not invalidate the raw.
69 // This shows that the read-exception for `&mut` applies even if the `Shr` item
70 // on the stack is not at the top.
71 fn mut_raw_mut() {
72     let mut x = 2;
73     {
74         let xref1 = &mut x;
75         let xraw = xref1 as *mut _;
76         let _xref2 = unsafe { &mut *xraw };
77         let _val = *xref1;
78         unsafe { *xraw = 4; }
79         // we can now use both xraw and xref1, for reading
80         assert_eq!(*xref1, 4);
81         assert_eq!(unsafe { *xraw }, 4);
82         assert_eq!(*xref1, 4);
83         assert_eq!(unsafe { *xraw }, 4);
84         // we cannot use xref2; see `compile-fail/stacked-borows/illegal_read4.rs`
85     }
86     assert_eq!(x, 4);
87 }
88
89 fn partially_invalidate_mut() {
90     let data = &mut (0u8, 0u8);
91     let reborrow = &mut *data as *mut (u8, u8);
92     let shard = unsafe { &mut (*reborrow).0 };
93     data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
94     *shard += 1; // so we can still use `shard`.
95     assert_eq!(*data, (1, 1));
96 }
97
98 // Make sure that we can handle the situation where a loaction is frozen when being dropped.
99 fn drop_after_sharing() {
100     let x = String::from("hello!");
101     let _len = x.len();
102 }
103
104 // Make sure that coercing &mut T to *const T produces a writeable pointer.
105 fn direct_mut_to_const_raw() {
106     // TODO: This is currently disabled, waiting on a decision on <https://github.com/rust-lang/rust/issues/56604>
107     /*let x = &mut 0;
108     let y: *const i32 = x;
109     unsafe { *(y as *mut i32) = 1; }
110     assert_eq!(*x, 1);
111     */
112 }
113
114 // Make sure that we can create two raw pointers from a mutable reference and use them both.
115 fn two_raw() { unsafe {
116     let x = &mut 0;
117     let y1 = x as *mut _;
118     let y2 = x as *mut _;
119     *y1 += 2;
120     *y2 += 1;
121 } }
122
123 // Make sure that creating a *mut does not invalidate existing shared references.
124 fn shr_and_raw() { unsafe {
125     use std::mem;
126     let x = &mut 0;
127     let y1: &i32 = mem::transmute(&*x); // launder lifetimes
128     let y2 = x as *mut _;
129     let _val = *y1;
130     *y2 += 1;
131 } }
132
133 fn disjoint_mutable_subborrows() {
134     struct Foo {
135         a: String,
136         b: Vec<u32>,
137     }
138
139     unsafe fn borrow_field_a<'a>(this:*mut Foo) -> &'a mut String {
140         &mut (*this).a
141     }
142
143     unsafe fn borrow_field_b<'a>(this:*mut Foo) -> &'a mut Vec<u32> {
144         &mut (*this).b
145     }
146
147     let mut foo = Foo {
148         a: "hello".into(),
149         b: vec![0,1,2],
150     };
151
152     let ptr = &mut foo as *mut Foo;
153
154     let a = unsafe{ borrow_field_a(ptr) };
155     let b = unsafe{ borrow_field_b(ptr) };
156     b.push(4);
157     a.push_str(" world");
158     eprintln!("{:?} {:?}", a, b);
159 }
160
161 fn raw_ref_to_part() {
162     struct Part {
163         _lame: i32,
164     }
165
166     #[repr(C)]
167     struct Whole {
168         part: Part,
169         extra: i32,
170     }
171
172     let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
173     let whole = ptr::raw_mut!(*Box::leak(it));
174     let part = unsafe { ptr::raw_mut!((*whole).part) };
175     let typed = unsafe { &mut *(part as *mut Whole) };
176     assert!(typed.extra == 42);
177     drop(unsafe { Box::from_raw(whole) });
178 }