better test the special exception for reading through unique when things are shared

This commit is contained in:
Ralf Jung 2018-11-07 21:08:20 +01:00
parent aa8f523df6
commit a94e197105
3 changed files with 41 additions and 5 deletions

View file

@ -167,13 +167,15 @@ impl<'tcx> Stack {
behind a barrier", bor))
}
(BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => {
// Found matching unique item.
// Found matching unique item. This is *always* required to use a `Uniq`:
// The item must still be on the stack.
if !is_write {
// As a special case, if we are reading and since we *did* find the `Uniq`,
// we try to pop less: We are happy with making a `Shr` or `Frz` active;
// that one will not mind concurrent reads.
// As a special case, if we are reading, let us see if it would be
// beneficial to pretend we are a raw pointer instead. If
// raw pointers are allowed to read while popping *less* than we
// would have to pop, there is no reason not to let them do this.
match self.reactivatable(Borrow::default(), is_write) {
// If we got something better that `idx`, use that
// If we got something better (popping less) that `idx`, use that
Ok(None) => return Ok(None),
Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)),
// Otherwise just go on.
@ -329,6 +331,8 @@ impl<'tcx> Stacks {
)))
}
// Sometimes we also need to be frozen.
// In this case we *both* push `Shr` and then freeze. This means that a `&mut`
// to `*const` to `*mut` cast through `&` actually works.
if frozen {
// Even shared refs can have uniq tags (after transmute). That's not an error
// but they do not get any freezing benefits.

View file

@ -0,0 +1,9 @@
// Using a raw invalidates derived `&mut` even for reading.
fn main() {
let mut x = 2;
let xref1 = &mut x;
let xraw = xref1 as *mut _;
let xref2 = unsafe { &mut *xraw };
let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs
let _illegal = *xref2; //~ ERROR does not exist on the stack
}

View file

@ -6,6 +6,7 @@ fn main() {
ref_raw_int_raw();
mut_shr_raw();
mut_raw_then_mut_shr();
mut_raw_mut();
}
// 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() {
}
assert_eq!(x, 4);
}
// 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);
}