| //@revisions: stack tree |
| //@compile-flags: -Zmiri-permissive-provenance |
| //@[tree]compile-flags: -Zmiri-tree-borrows |
| use std::ptr; |
| |
| // 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); |
| } |
| |
| /// Ensure that we do not just pick the topmost possible item on int2ptr casts. |
| fn example(variant: bool) { |
| unsafe { |
| fn not_so_innocent(x: &mut u32) -> usize { |
| let x_raw4 = x as *mut u32; |
| x_raw4.expose_provenance() |
| } |
| |
| let mut c = 42u32; |
| |
| let x_unique1 = &mut c; |
| // stack: [..., Unique(1)] |
| |
| let x_raw2 = x_unique1 as *mut u32; |
| let x_raw2_addr = x_raw2.expose_provenance(); |
| // stack: [..., Unique(1), SharedRW(2)] |
| |
| let x_unique3 = &mut *x_raw2; |
| // stack: [.., Unique(1), SharedRW(2), Unique(3)] |
| |
| assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); |
| // stack: [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] |
| |
| // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). |
| // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). |
| // And indeed if `variant == true` it is the only possible choice. |
| // But if `variant == false` then 2 is the only possible choice! |
| let x_wildcard = ptr::with_exposed_provenance_mut::<i32>(x_raw2_addr); |
| |
| if variant { |
| // If we picked 2, this will invalidate 3. |
| *x_wildcard = 10; |
| // Now we use 3. Only possible if above we picked 4. |
| *x_unique3 = 12; |
| } else { |
| // This invalidates tag 4. |
| *x_unique3 = 10; |
| // Now try to write with the "guessed" tag; it must be 2. |
| *x_wildcard = 12; |
| } |
| } |
| } |
| |
| fn test() { |
| unsafe { |
| let root = &mut 42; |
| let root_raw = root as *mut i32; |
| let addr1 = root_raw as usize; |
| let child = &mut *root_raw; |
| let child_raw = child as *mut i32; |
| let addr2 = child_raw as usize; |
| assert_eq!(addr1, addr2); |
| // First use child. |
| *(addr2 as *mut i32) -= 2; // picks child_raw |
| *child -= 2; |
| // Then use root. |
| *(addr1 as *mut i32) += 2; // picks root_raw |
| *root += 2; |
| // Value should be unchanged. |
| assert_eq!(*root, 42); |
| } |
| } |
| |
| fn main() { |
| ref_raw_int_raw(); |
| example(false); |
| example(true); |
| test(); |
| } |