| //@ known-bug: #107975 |
| //@ compile-flags: -Copt-level=2 |
| //@ run-pass |
| //@ ignore-backends: gcc |
| |
| // https://github.com/rust-lang/rust/issues/107975#issuecomment-1431758601 |
| |
| use std::cell::{Ref, RefCell}; |
| |
| fn main() { |
| let a: usize = { |
| let v = 0u8; |
| &v as *const _ as usize |
| }; |
| let b: usize = { |
| let v = 0u8; |
| &v as *const _ as usize |
| }; |
| let i: usize = b - a; |
| |
| // A surprise tool that will help us later. |
| let arr = [ |
| RefCell::new(Some(Box::new(1u8))), |
| RefCell::new(None), |
| RefCell::new(None), |
| RefCell::new(None), |
| ]; |
| |
| // `i` is not 0 |
| assert_ne!(i, 0); |
| |
| // Let's borrow the `i`-th element. |
| // If `i` is out of bounds, indexing will panic. |
| let r: Ref<Option<Box<u8>>> = arr[i].borrow(); |
| |
| // If we got here, it means `i` was in bounds. |
| // Now, two options are possible: |
| // EITHER `i` is not 0 (as we have asserted above), |
| // so the unwrap will panic, because only the 0-th element is `Some` |
| // OR the assert lied, `i` *is* 0, and the `unwrap` will not panic. |
| let r: &Box<u8> = r.as_ref().unwrap(); |
| |
| // If we got here, it means `i` *was* actually 0. |
| // Let's ignore the fact that the assert has lied |
| // and try to take a mutable reference to the 0-th element. |
| // `borrow_mut` should panic, because we are sill holding on |
| // to a shared `Ref` for the same `RefCell`. |
| *arr[0].borrow_mut() = None; |
| |
| // But it doesn't panic! |
| // We have successfully replaced `Some(Box)` with `None`, |
| // while holding a shared reference to it. |
| // No unsafe involved. |
| |
| // The `Box` has been deallocated by now, so this is a dangling reference! |
| let r: &u8 = &*r; |
| println!("{:p}", r); |
| println!("{}", i); |
| |
| // The following might segfault. Or it might not. |
| // Depends on the platform semantics |
| // and whatever happened to the pointed-to memory after deallocation. |
| // let u: u8 = *r; |
| // println!("{u}"); |
| } |