Merge pull request #4306 from yoctocell/fix-unsafecell-inside-box

Tree Borrows: Correctly handle interior mutable data in `Box`
This commit is contained in:
Ralf Jung 2025-05-05 11:58:34 +00:00 committed by GitHub
commit 70ef2504b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 43 additions and 1 deletions

View file

@ -168,7 +168,7 @@ impl<'tcx> NewPermission {
pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
// Regular `Unpin` box, give it `noalias` but only a weak protector
// because it is valid to deallocate it within the function.
let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env());
let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
let protected = kind == RetagKind::FnEntry;
let initial_state = Permission::new_reserved(ty_is_freeze, protected);
Self {

View file

@ -0,0 +1,35 @@
//@compile-flags: -Zmiri-tree-borrows
#![feature(box_as_ptr)]
#[path = "../../utils/mod.rs"]
#[macro_use]
mod utils;
use std::cell::UnsafeCell;
pub fn main() {
let cell = UnsafeCell::new(42);
let box1 = Box::new(cell);
unsafe {
let ptr1: *mut UnsafeCell<i32> = Box::into_raw(box1);
name!(ptr1);
let mut box2 = Box::from_raw(ptr1);
// `ptr2` will be a descendant of `ptr1`.
let ptr2: *mut UnsafeCell<i32> = Box::as_mut_ptr(&mut box2);
name!(ptr2);
// We perform a write through `x`.
// Because `ptr1` is ReservedIM, a child write will make it transition to Active.
// Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it.
let x = (*ptr1).get();
*x = 1;
// We can still read from `ptr2`.
let val = *(*ptr2).get();
assert_eq!(val, 1);
let alloc_id = alloc_id!(ptr1);
print_state!(alloc_id);
}
}

View file

@ -0,0 +1,7 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 4
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=ptr1>
| ReIM| └────<TAG=ptr2>
──────────────────────────────────────────────────