summaryrefslogtreecommitdiff
path: root/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
blob: d7d7d1f97d6e5e924b91b094dfd5d53922d25223 (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//@compile-flags: -Zmiri-retag-fields
#![feature(allocator_api)]
use std::ptr;

// Test various stacked-borrows-related things.
fn main() {
    read_does_not_invalidate1();
    read_does_not_invalidate2();
    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();
    disjoint_mutable_subborrows();
    raw_ref_to_part();
    array_casts();
    mut_below_shr();
    wide_raw_ptr_in_tuple();
    not_unpin_not_protected();
}

// 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);
}

// 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-borrows/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 location 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() {
    // TODO: This is currently disabled, waiting on a decision on <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;
        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;
        let x = &mut 0;
        let y1: &i32 = mem::transmute(&*x); // launder lifetimes
        let y2 = x as *mut _;
        let _val = *y1;
        *y2 += 1;
    }
}

fn disjoint_mutable_subborrows() {
    struct Foo {
        a: String,
        b: Vec<u32>,
    }

    unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String {
        &mut (*this).a
    }

    unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec<u32> {
        &mut (*this).b
    }

    let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] };

    let ptr = &mut foo as *mut Foo;

    let a = unsafe { borrow_field_a(ptr) };
    let b = unsafe { borrow_field_b(ptr) };
    b.push(4);
    a.push_str(" world");
    eprintln!("{:?} {:?}", a, b);
}

fn raw_ref_to_part() {
    struct Part {
        _lame: i32,
    }

    #[repr(C)]
    struct Whole {
        part: Part,
        extra: i32,
    }

    let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
    let whole = ptr::addr_of_mut!(*Box::leak(it));
    let part = unsafe { ptr::addr_of_mut!((*whole).part) };
    let typed = unsafe { &mut *(part as *mut Whole) };
    assert!(typed.extra == 42);
    drop(unsafe { Box::from_raw(whole) });
}

/// When casting an array reference to a raw element ptr, that should cover the whole array.
fn array_casts() {
    let mut x: [usize; 2] = [0, 0];
    let p = &mut x as *mut usize;
    unsafe {
        *p.add(1) = 1;
    }

    let x: [usize; 2] = [0, 1];
    let p = &x as *const usize;
    assert_eq!(unsafe { *p.add(1) }, 1);
}

/// Transmuting &&i32 to &&mut i32 is fine.
fn mut_below_shr() {
    let x = 0;
    let y = &x;
    let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) };
    let r = &**p;
    let _val = *r;
}

fn wide_raw_ptr_in_tuple() {
    let mut x: Box<dyn std::any::Any> = Box::new("ouch");
    let r = &mut *x as *mut dyn std::any::Any;
    // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw
    // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and
    // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong.
    let pair = (r, &0);
    let r = unsafe { &mut *pair.0 };
    // Make sure the fn ptr part of the vtable is still fine.
    r.type_id();
}

fn not_unpin_not_protected() {
    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
    // don't add protectors. (We could, but until we have a better idea for where we want to go with
    // the self-referential-generator situation, it does not seem worth the potential trouble.)
    use std::marker::PhantomPinned;

    pub struct NotUnpin(i32, PhantomPinned);

    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
        // `f` may mutate, but it may not deallocate!
        f(x)
    }

    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
        let raw = x as *mut _;
        drop(unsafe { Box::from_raw(raw) });
    });
}