about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCAD97 <cad97@cad97.com>2020-07-14 15:17:55 -0400
committerCAD97 <cad97@cad97.com>2020-09-12 10:38:32 -0500
commit5e7406c9569dce75a042ce079918cf03cfca842a (patch)
tree3badd15845e69aa4a359aaf1c4ffa9cd25f99f01
parent0c61ce2cf0560577923abafab2e5bfce14516525 (diff)
downloadrust-5e7406c9569dce75a042ce079918cf03cfca842a.tar.gz
rust-5e7406c9569dce75a042ce079918cf03cfca842a.zip
Adjust sync::Weak::from_raw to support unsized T
-rw-r--r--library/alloc/src/sync.rs23
1 files changed, 12 insertions, 11 deletions
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 6a240fbb42a..06dec6f01f8 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1629,17 +1629,18 @@ impl<T> Weak<T> {
     /// [`forget`]: std::mem::forget
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        if ptr.is_null() {
-            Self::new()
-        } else {
-            // See Arc::from_raw for details
-            unsafe {
-                let offset = data_offset(ptr);
-                let fake_ptr = ptr as *mut ArcInner<T>;
-                let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
-                Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
-            }
-        }
+        // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
+        // See Weak::as_ptr for context on how the input pointer is derived.
+        let offset = unsafe { data_offset(ptr) };
+
+        // Reverse the offset to find the original ArcInner.
+        // SAFETY: we use wrapping_offset here because the pointer may be dangling (iff T: Sized)
+        let ptr = unsafe {
+            set_data_ptr(ptr as *mut ArcInner<T>, (ptr as *mut u8).wrapping_offset(-offset))
+        };
+
+        // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
+        unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } }
     }
 }