forked from rust-lang/miri
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstacked-borrows.rs
More file actions
140 lines (130 loc) · 4.56 KB
/
Copy pathstacked-borrows.rs
File metadata and controls
140 lines (130 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Test various stacked-borrows-related things.
fn main() {
read_does_not_invalidate1();
read_does_not_invalidate2();
ref_raw_int_raw();
mut_raw_then_mut_shr();
mut_shr_then_mut_raw();
mut_raw_mut();
partially_invalidate_mut();
drop_after_sharing();
direct_mut_to_const_raw();
two_raw();
shr_and_raw();
}
// Make sure that reading from an `&mut` does, like reborrowing to `&`,
// NOT invalidate other reborrows.
fn read_does_not_invalidate1() {
fn foo(x: &mut (i32, i32)) -> &i32 {
let xraw = x as *mut (i32, i32);
let ret = unsafe { &(*xraw).1 };
let _val = x.1; // we just read, this does NOT invalidate the reborrows.
ret
}
assert_eq!(*foo(&mut (1, 2)), 2);
}
// Same as above, but this time we first create a raw, then read from `&mut`
// and then freeze from the raw.
fn read_does_not_invalidate2() {
fn foo(x: &mut (i32, i32)) -> &i32 {
let xraw = x as *mut (i32, i32);
let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
let ret = unsafe { &(*xraw).1 };
ret
}
assert_eq!(*foo(&mut (1, 2)), 2);
}
// Just to make sure that casting a ref to raw, to int and back to raw
// and only then using it works. This rules out ideas like "do escape-to-raw lazily";
// after casting to int and back, we lost the tag that could have let us do that.
fn ref_raw_int_raw() {
let mut x = 3;
let xref = &mut x;
let xraw = xref as *mut i32 as usize as *mut i32;
assert_eq!(unsafe { *xraw }, 3);
}
// Escape a mut to raw, then share the same mut and use the share, then the raw.
// That should work.
fn mut_raw_then_mut_shr() {
let mut x = 2;
let xref = &mut x;
let xraw = &mut *xref as *mut _;
let xshr = &*xref;
assert_eq!(*xshr, 2);
unsafe { *xraw = 4; }
assert_eq!(x, 4);
}
// Create first a shared reference and then a raw pointer from a `&mut`
// should permit mutation through that raw pointer.
fn mut_shr_then_mut_raw() {
let xref = &mut 2;
let _xshr = &*xref;
let xraw = xref as *mut _;
unsafe { *xraw = 3; }
assert_eq!(*xref, 3);
}
// Ensure that if we derive from a mut a raw, and then from that a mut,
// and then read through the original mut, that does not invalidate the raw.
// This shows that the read-exception for `&mut` applies even if the `Shr` item
// on the stack is not at the top.
fn mut_raw_mut() {
let mut x = 2;
{
let xref1 = &mut x;
let xraw = xref1 as *mut _;
let _xref2 = unsafe { &mut *xraw };
let _val = *xref1;
unsafe { *xraw = 4; }
// we can now use both xraw and xref1, for reading
assert_eq!(*xref1, 4);
assert_eq!(unsafe { *xraw }, 4);
assert_eq!(*xref1, 4);
assert_eq!(unsafe { *xraw }, 4);
// we cannot use xref2; see `compile-fail/stacked-borows/illegal_read4.rs`
}
assert_eq!(x, 4);
}
fn partially_invalidate_mut() {
let data = &mut (0u8, 0u8);
let reborrow = &mut *data as *mut (u8, u8);
let shard = unsafe { &mut (*reborrow).0 };
data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
*shard += 1; // so we can still use `shard`.
assert_eq!(*data, (1, 1));
}
// Make sure that we can handle the situation where a loaction is frozen when being dropped.
fn drop_after_sharing() {
let x = String::from("hello!");
let _len = x.len();
}
// Make sure that coercing &mut T to *const T produces a writeable pointer.
fn direct_mut_to_const_raw() {
// FIXME: This is currently disabled, waiting on a fix for <https://github.com/rust-lang/rust/issues/56604>
/*let x = &mut 0;
let y: *const i32 = x;
unsafe { *(y as *mut i32) = 1; }
assert_eq!(*x, 1);
*/
}
// Make sure that we can create two raw pointers from a mutable reference and use them both.
fn two_raw() { unsafe {
let x = &mut 0;
// Given the implicit reborrows, the only reason this currently works is that we
// do not track raw pointers: The creation of `y2` reborrows `x` and thus pops
// `y1` off the stack.
let y1 = x as *mut _;
let y2 = x as *mut _;
*y1 += 2;
*y2 += 1;
} }
// Make sure that creating a *mut does not invalidate existing shared references.
fn shr_and_raw() { /* unsafe {
use std::mem;
// FIXME: This is currently disabled because "as *mut _" incurs a reborrow.
let x = &mut 0;
let y1: &i32 = mem::transmute(&*x); // launder lifetimes
let y2 = x as *mut _;
let _val = *y1;
*y2 += 1;
// TODO: Once this works, add compile-fail test that tries to read from y1 again.
} */ }