about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2019-02-16 00:55:54 +0800
committerkennytm <kennytm@gmail.com>2019-02-16 14:11:41 +0800
commit13b055d5db67ab6c88d6379b7677069482db6077 (patch)
treec7dcd62b3c74dbf6e0a303cdbd4844ed53467d6a
parent092d191965597c80e01bae7029324bce5b994b8f (diff)
parent719be246ae708508a19436a0b8ee1be29882e21e (diff)
downloadrust-13b055d5db67ab6c88d6379b7677069482db6077.tar.gz
rust-13b055d5db67ab6c88d6379b7677069482db6077.zip
Rollup merge of #58429 - RalfJung:box, r=TimNN
fix Box::into_unique effecitvely transmuting to a raw ptr

Miri/Stacked Borrows treat `Box` specially: they assert that it is unique, and tag it appropriately. However, currently, `Box::into_inner` is not aware of that and returns a raw pointer (wrapped in a `Unique`) that carries the same tag as the box, meaning it carries a `Uniq` tag. This leads to all sorts of problems when people use the raw pointer they get out of the `Unique` type.

In the future, it'd be interesting to make `Unique` also carry some kind of uniqueness. In that case, something like this would instead be needed whenever a raw pointer is extracted from a `Unique`. However, that is out-of-scope for the current version of Stacked Borrows. So until then, this changes `into_unique` to perform a proper reference-to-raw-ptr-cast, which clears the tag.
-rw-r--r--src/liballoc/boxed.rs11
1 files changed, 8 insertions, 3 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 51549f92d4d..0cd2373c7f0 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -202,10 +202,15 @@ impl<T: ?Sized> Box<T> {
     #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")]
     #[inline]
     #[doc(hidden)]
-    pub fn into_unique(b: Box<T>) -> Unique<T> {
-        let unique = b.0;
+    pub fn into_unique(mut b: Box<T>) -> Unique<T> {
+        // Box is kind-of a library type, but recognized as a "unique pointer" by
+        // Stacked Borrows.  This function here corresponds to "reborrowing to
+        // a raw pointer", but there is no actual reborrow here -- so
+        // without some care, the pointer we are returning here still carries
+        // the `Uniq` tag.  We round-trip through a mutable reference to avoid that.
+        let unique = unsafe { b.0.as_mut() as *mut T };
         mem::forget(b);
-        unique
+        unsafe { Unique::new_unchecked(unique) }
     }
 
     /// Consumes and leaks the `Box`, returning a mutable reference,