Skip to content

Commit

Permalink
Use ManuallyDrop with bumpalo's Box instead of mem::forget
Browse files Browse the repository at this point in the history
Miri now reports UB with some uses of bumpalo's Box where it did not
before: rust-lang/miri#2704

The previous behavior of Miri was a false negative. rustc applies
noalias to newtype wrappers around &mut, so Miri has to retag &mut when
passed by value to a function even if it is in a wrapper struct, such as
bumpalo's Box. mem::forget is a common aliasing footgun, because for a
unique-owning wrapper like Box, leaking an RAII handle re-asserts the
uniqueness of the handle as it is sent to the void. Ouch.

ManuallyDrop solves this problem.
  • Loading branch information
saethlin committed Nov 28, 2022
1 parent 5805a29 commit d325e2c
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 8 deletions.
15 changes: 7 additions & 8 deletions src/boxed.rs
Expand Up @@ -130,7 +130,7 @@ use {
future::Future,
hash::{Hash, Hasher},
iter::FusedIterator,
mem,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
pin::Pin,
task::{Context, Poll},
Expand Down Expand Up @@ -280,9 +280,8 @@ impl<'a, T: ?Sized> Box<'a, T> {
/// ```
#[inline]
pub fn into_raw(b: Box<'a, T>) -> *mut T {
let ptr = b.0 as *mut T;
mem::forget(b);
ptr
let mut b = ManuallyDrop::new(b);
b.deref_mut().0 as *mut T
}

/// Consumes and leaks the `Box`, returning a mutable reference,
Expand Down Expand Up @@ -662,20 +661,20 @@ impl<'a, F: ?Sized + Future + Unpin> Future for Box<'a, F> {

/// This impl replaces unsize coercion.
impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
fn from(mut arr: Box<'a, [T; N]>) -> Box<'a, [T]> {
fn from(arr: Box<'a, [T; N]>) -> Box<'a, [T]> {
let mut arr = ManuallyDrop::new(arr);
let ptr = core::ptr::slice_from_raw_parts_mut(arr.as_mut_ptr(), N);
mem::forget(arr);
unsafe { Box::from_raw(ptr) }
}
}

/// This impl replaces unsize coercion.
impl<'a, T, const N: usize> TryFrom<Box<'a, [T]>> for Box<'a, [T; N]> {
type Error = Box<'a, [T]>;
fn try_from(mut slice: Box<'a, [T]>) -> Result<Box<'a, [T; N]>, Box<'a, [T]>> {
fn try_from(slice: Box<'a, [T]>) -> Result<Box<'a, [T; N]>, Box<'a, [T]>> {
if slice.len() == N {
let mut slice = ManuallyDrop::new(slice);
let ptr = slice.as_mut_ptr() as *mut [T; N];
mem::forget(slice);
Ok(unsafe { Box::from_raw(ptr) })
} else {
Err(slice)
Expand Down
14 changes: 14 additions & 0 deletions tests/all/boxed.rs
@@ -0,0 +1,14 @@
#![cfg(feature = "boxed")]

use bumpalo::Bump;
use bumpalo::boxed::Box;

#[test]
fn into_raw_aliasing() {
let bump = Bump::new();
let boxed = Box::new_in(1, &bump);
let raw = Box::into_raw(boxed);

let mut_ref = unsafe { &mut *raw };
dbg!(mut_ref);
}
1 change: 1 addition & 0 deletions tests/all/main.rs
Expand Up @@ -13,5 +13,6 @@ mod tests;
mod try_alloc_try_with;
mod try_alloc_with;
mod vec;
mod boxed;

fn main() {}

0 comments on commit d325e2c

Please sign in to comment.