mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 04:57:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			64 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			64 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //@ known-bug: #107975
 | |
| //@ compile-flags: -Copt-level=2
 | |
| //@ run-pass
 | |
| 
 | |
| // 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);
 | |
| 
 | |
|     // 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}");
 | |
| }
 | 
