|
| 1 | +//@ known-bug: #107975 |
| 2 | +//@ compile-flags: -Copt-level=2 |
| 3 | +//@ run-pass |
| 4 | + |
| 5 | +// https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 |
| 6 | + |
| 7 | +use std::cell::{Ref, RefCell}; |
| 8 | + |
| 9 | +fn main() { |
| 10 | + let a: usize = { |
| 11 | + let v = 0u8; |
| 12 | + &v as *const _ as usize |
| 13 | + }; |
| 14 | + let b: usize = { |
| 15 | + let v = 0u8; |
| 16 | + &v as *const _ as usize |
| 17 | + }; |
| 18 | + let i: usize = b - a; |
| 19 | + |
| 20 | + // A surprise tool that will help us later. |
| 21 | + let arr = [ |
| 22 | + RefCell::new(Some(Box::new(1u8))), |
| 23 | + RefCell::new(None), |
| 24 | + RefCell::new(None), |
| 25 | + RefCell::new(None), |
| 26 | + ]; |
| 27 | + |
| 28 | + // `i` is not 0 |
| 29 | + assert_ne!(i, 0); |
| 30 | + |
| 31 | + // Let's borrow the `i`-th element. |
| 32 | + // If `i` is out of bounds, indexing will panic. |
| 33 | + let r: Ref<Option<Box<u8>>> = arr[i].borrow(); |
| 34 | + |
| 35 | + // If we got here, it means `i` was in bounds. |
| 36 | + // Now, two options are possible: |
| 37 | + // EITHER `i` is not 0 (as we have asserted above), |
| 38 | + // so the unwrap will panic, because only the 0-th element is `Some` |
| 39 | + // OR the assert lied, `i` *is* 0, and the `unwrap` will not panic. |
| 40 | + let r: &Box<u8> = r.as_ref().unwrap(); |
| 41 | + |
| 42 | + // If we got here, it means `i` *was* actually 0. |
| 43 | + // Let's ignore the fact that the assert has lied |
| 44 | + // and try to take a mutable reference to the 0-th element. |
| 45 | + // `borrow_mut` should panic, because we are sill holding on |
| 46 | + // to a shared `Ref` for the same `RefCell`. |
| 47 | + *arr[0].borrow_mut() = None; |
| 48 | + |
| 49 | + // But it doesn't panic! |
| 50 | + // We have successfully replaced `Some(Box)` with `None`, |
| 51 | + // while holding a shared reference to it. |
| 52 | + // No unsafe involved. |
| 53 | + |
| 54 | + // The `Box` has been deallocated by now, so this is a dangling reference! |
| 55 | + let r: &u8 = &*r; |
| 56 | + println!("{:p}", r); |
| 57 | + |
| 58 | + // The following might segfault. Or it might not. |
| 59 | + // Depends on the platform semantics |
| 60 | + // and whatever happened to the pointed-to memory after deallocation. |
| 61 | + // let u: u8 = *r; |
| 62 | + // println!("{u}"); |
| 63 | +} |
0 commit comments