From d325e2c94576f6806508751f945ba5985661b721 Mon Sep 17 00:00:00 2001
From: Ben Kimock <kimockb@gmail.com>
Date: Mon, 28 Nov 2022 18:29:58 -0500
Subject: [PATCH] Use ManuallyDrop with bumpalo's Box instead of mem::forget

Miri now reports UB with some uses of bumpalo's Box where it did not
before: https://github.com/rust-lang/miri/issues/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.
---
 src/boxed.rs       | 15 +++++++--------
 tests/all/boxed.rs | 14 ++++++++++++++
 tests/all/main.rs  |  1 +
 3 files changed, 22 insertions(+), 8 deletions(-)
 create mode 100644 tests/all/boxed.rs

diff --git a/src/boxed.rs b/src/boxed.rs
index cf9f4d6..af0737c 100644
--- a/src/boxed.rs
+++ b/src/boxed.rs
@@ -130,7 +130,7 @@ use {
             future::Future,
             hash::{Hash, Hasher},
             iter::FusedIterator,
-            mem,
+            mem::ManuallyDrop,
             ops::{Deref, DerefMut},
             pin::Pin,
             task::{Context, Poll},
@@ -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,
@@ -662,9 +661,9 @@ 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) }
     }
 }
@@ -672,10 +671,10 @@ impl<'a, T, const N: usize> From<Box<'a, [T; N]>> for Box<'a, [T]> {
 /// 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)
diff --git a/tests/all/boxed.rs b/tests/all/boxed.rs
new file mode 100644
index 0000000..54458fb
--- /dev/null
+++ b/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);
+}
diff --git a/tests/all/main.rs b/tests/all/main.rs
index 716abc6..00de4f3 100644
--- a/tests/all/main.rs
+++ b/tests/all/main.rs
@@ -13,5 +13,6 @@ mod tests;
 mod try_alloc_try_with;
 mod try_alloc_with;
 mod vec;
+mod boxed;
 
 fn main() {}