Rollup merge of #124013 - RalfJung:box-to-raw, r=oli-obk
Box::into_raw: make Miri understand that this is a box-to-raw cast Turns out https://github.com/rust-lang/rust/pull/122647 went a bit too far in cleaning up `Box`... we still need a hack in `Box::into_raw`. The nicer fix would be to make Stacked Borrows not care about reference-to-raw-pointer casts, but it's unclear whether that will ever be possible without going to full Tree Borrows. Fixes https://github.com/rust-lang/miri/issues/3473.
This commit is contained in:
commit
51cfa95668
5 changed files with 48 additions and 4 deletions
|
@ -1058,7 +1058,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||||
#[stable(feature = "box_raw", since = "1.4.0")]
|
#[stable(feature = "box_raw", since = "1.4.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_raw(b: Self) -> *mut T {
|
pub fn into_raw(b: Self) -> *mut T {
|
||||||
Self::into_raw_with_allocator(b).0
|
// Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here.
|
||||||
|
unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
|
/// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
|
||||||
|
@ -1112,7 +1113,10 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||||
pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
|
pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
|
||||||
let mut b = mem::ManuallyDrop::new(b);
|
let mut b = mem::ManuallyDrop::new(b);
|
||||||
// We carefully get the raw pointer out in a way that Miri's aliasing model understands what
|
// We carefully get the raw pointer out in a way that Miri's aliasing model understands what
|
||||||
// is happening: using the primitive "deref" of `Box`.
|
// is happening: using the primitive "deref" of `Box`. In case `A` is *not* `Global`, we
|
||||||
|
// want *no* aliasing requirements here!
|
||||||
|
// In case `A` *is* `Global`, this does not quite have the right behavior; `into_raw`
|
||||||
|
// works around that.
|
||||||
let ptr = addr_of_mut!(**b);
|
let ptr = addr_of_mut!(**b);
|
||||||
let alloc = unsafe { ptr::read(&b.1) };
|
let alloc = unsafe { ptr::read(&b.1) };
|
||||||
(ptr, alloc)
|
(ptr, alloc)
|
||||||
|
|
|
@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
||||||
|
|
|
|
||||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
|
||||||
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
|
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
|
||||||
--> $DIR/newtype_pair_retagging.rs:LL:CC
|
--> $DIR/newtype_pair_retagging.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | let ptr = Box::into_raw(Box::new(0i32));
|
LL | let ptr = Box::into_raw(Box::new(0i32));
|
||||||
|
|
|
@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc)
|
||||||
|
|
|
|
||||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
|
||||||
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||||
help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
|
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
|
||||||
--> $DIR/newtype_retagging.rs:LL:CC
|
--> $DIR/newtype_retagging.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | let ptr = Box::into_raw(Box::new(0i32));
|
LL | let ptr = Box::into_raw(Box::new(0i32));
|
||||||
|
|
28
src/tools/miri/tests/pass/issues/issue-miri-3473.rs
Normal file
28
src/tools/miri/tests/pass/issues/issue-miri-3473.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//@revisions: stack tree
|
||||||
|
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Node {
|
||||||
|
_meta: UnsafeCell<usize>,
|
||||||
|
value: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
fn value(&self) -> &usize {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This used to cause Stacked Borrows errors because of trouble around conversion
|
||||||
|
/// from Box to raw pointer.
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
let a = Box::into_raw(Box::new(Node::default()));
|
||||||
|
let ptr = &*a;
|
||||||
|
*UnsafeCell::raw_get(a.cast::<UnsafeCell<usize>>()) = 2;
|
||||||
|
assert_eq!(*ptr.value(), 0);
|
||||||
|
drop(Box::from_raw(a));
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ fn main() {
|
||||||
wide_raw_ptr_in_tuple();
|
wide_raw_ptr_in_tuple();
|
||||||
not_unpin_not_protected();
|
not_unpin_not_protected();
|
||||||
write_does_not_invalidate_all_aliases();
|
write_does_not_invalidate_all_aliases();
|
||||||
|
box_into_raw_allows_interior_mutable_alias();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that reading from an `&mut` does, like reborrowing to `&`,
|
// Make sure that reading from an `&mut` does, like reborrowing to `&`,
|
||||||
|
@ -263,3 +264,14 @@ fn write_does_not_invalidate_all_aliases() {
|
||||||
other::lib2();
|
other::lib2();
|
||||||
assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated
|
assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn box_into_raw_allows_interior_mutable_alias() { unsafe {
|
||||||
|
let b = Box::new(std::cell::Cell::new(42));
|
||||||
|
let raw = Box::into_raw(b);
|
||||||
|
let c = &*raw;
|
||||||
|
let d = raw.cast::<i32>(); // bypassing `Cell` -- only okay in Miri tests
|
||||||
|
// `c` and `d` should permit arbitrary aliasing with each other now.
|
||||||
|
*d = 1;
|
||||||
|
c.set(2);
|
||||||
|
drop(Box::from_raw(raw));
|
||||||
|
} }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue