From c842f02dee81e52f3b63a8b46021a8e18f143a7e Mon Sep 17 00:00:00 2001 From: cad97 Date: Sun, 15 Dec 2019 17:59:09 -0500 Subject: [PATCH 1/2] Use pointer offset instead of deref for A/Rc::into_raw --- src/liballoc/rc.rs | 9 +++++++-- src/liballoc/sync.rs | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 1ff1c3c834f4e..0205c40829930 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -571,9 +571,14 @@ impl Rc { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub fn into_raw(this: Self) -> *const T { - let ptr: *const T = &*this; + let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); + let fake_ptr = ptr as *mut T; mem::forget(this); - ptr + + unsafe { + let offset = data_offset(&(*ptr).value); + set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset)) + } } /// Constructs an `Rc` from a raw pointer. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 19b0086fa333c..de56cb300d38c 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -551,9 +551,14 @@ impl Arc { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub fn into_raw(this: Self) -> *const T { - let ptr: *const T = &*this; + let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); + let fake_ptr = ptr as *mut T; mem::forget(this); - ptr + + unsafe { + let offset = data_offset(&(*ptr).data); + set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset)) + } } /// Constructs an `Arc` from a raw pointer. From eb77f7ec6e9460c1ca70fbb7bb655f1a0a1bacfc Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 17 Dec 2019 15:52:13 -0500 Subject: [PATCH 2/2] Add internal safety docs to (A)Rc::into_raw --- src/liballoc/rc.rs | 5 +++++ src/liballoc/sync.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 0205c40829930..8c70b0a913a98 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -575,6 +575,11 @@ impl Rc { let fake_ptr = ptr as *mut T; mem::forget(this); + // SAFETY: This cannot go through Deref::deref. + // Instead, we manually offset the pointer rather than manifesting a reference. + // This is so that the returned pointer retains the same provenance as our pointer. + // This is required so that e.g. `get_mut` can write through the pointer + // after the Rc is recovered through `from_raw`. unsafe { let offset = data_offset(&(*ptr).value); set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset)) diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index de56cb300d38c..5c1fa17a626d1 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -555,6 +555,11 @@ impl Arc { let fake_ptr = ptr as *mut T; mem::forget(this); + // SAFETY: This cannot go through Deref::deref. + // Instead, we manually offset the pointer rather than manifesting a reference. + // This is so that the returned pointer retains the same provenance as our pointer. + // This is required so that e.g. `get_mut` can write through the pointer + // after the Arc is recovered through `from_raw`. unsafe { let offset = data_offset(&(*ptr).data); set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))