Skip to content

Commit a94e197

Browse files
committed
better test the special exception for reading through unique when things are shared
1 parent aa8f523 commit a94e197

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

src/stacked_borrows.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,15 @@ impl<'tcx> Stack {
167167
behind a barrier", bor))
168168
}
169169
(BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => {
170-
// Found matching unique item.
170+
// Found matching unique item. This is *always* required to use a `Uniq`:
171+
// The item must still be on the stack.
171172
if !is_write {
172-
// As a special case, if we are reading and since we *did* find the `Uniq`,
173-
// we try to pop less: We are happy with making a `Shr` or `Frz` active;
174-
// that one will not mind concurrent reads.
173+
// As a special case, if we are reading, let us see if it would be
174+
// beneficial to pretend we are a raw pointer instead. If
175+
// raw pointers are allowed to read while popping *less* than we
176+
// would have to pop, there is no reason not to let them do this.
175177
match self.reactivatable(Borrow::default(), is_write) {
176-
// If we got something better that `idx`, use that
178+
// If we got something better (popping less) that `idx`, use that
177179
Ok(None) => return Ok(None),
178180
Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)),
179181
// Otherwise just go on.
@@ -329,6 +331,8 @@ impl<'tcx> Stacks {
329331
)))
330332
}
331333
// Sometimes we also need to be frozen.
334+
// In this case we *both* push `Shr` and then freeze. This means that a `&mut`
335+
// to `*const` to `*mut` cast through `&` actually works.
332336
if frozen {
333337
// Even shared refs can have uniq tags (after transmute). That's not an error
334338
// but they do not get any freezing benefits.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Using a raw invalidates derived `&mut` even for reading.
2+
fn main() {
3+
let mut x = 2;
4+
let xref1 = &mut x;
5+
let xraw = xref1 as *mut _;
6+
let xref2 = unsafe { &mut *xraw };
7+
let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs
8+
let _illegal = *xref2; //~ ERROR does not exist on the stack
9+
}

tests/run-pass/stacked-borrows.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ fn main() {
66
ref_raw_int_raw();
77
mut_shr_raw();
88
mut_raw_then_mut_shr();
9+
mut_raw_mut();
910
}
1011

1112
// Deref a raw ptr to access a field of a large struct, where the field
@@ -76,3 +77,25 @@ fn mut_raw_then_mut_shr() {
7677
}
7778
assert_eq!(x, 4);
7879
}
80+
81+
// Ensure that if we derive from a mut a raw, and then from that a mut,
82+
// and then read through the original mut, that does not invalidate the raw.
83+
// This shows that the read-exception for `&mut` applies even if the `Shr` item
84+
// on the stack is not at the top.
85+
fn mut_raw_mut() {
86+
let mut x = 2;
87+
{
88+
let xref1 = &mut x;
89+
let xraw = xref1 as *mut _;
90+
let _xref2 = unsafe { &mut *xraw };
91+
let _val = *xref1;
92+
unsafe { *xraw = 4; }
93+
// we can now use both xraw and xref1, for reading
94+
assert_eq!(*xref1, 4);
95+
assert_eq!(unsafe { *xraw }, 4);
96+
assert_eq!(*xref1, 4);
97+
assert_eq!(unsafe { *xraw }, 4);
98+
// we cannot use xref2; see `compile-fail/stacked-borows/illegal_read4.rs`
99+
}
100+
assert_eq!(x, 4);
101+
}

0 commit comments

Comments
 (0)