]> git.lizzy.rs Git - rust.git/commitdiff
Adjust sync::Weak::from_raw to support unsized T
authorCAD97 <cad97@cad97.com>
Tue, 14 Jul 2020 19:17:55 +0000 (15:17 -0400)
committerCAD97 <cad97@cad97.com>
Sat, 12 Sep 2020 15:38:32 +0000 (10:38 -0500)
library/alloc/src/sync.rs

index 6a240fbb42a998228b01c44a45a9dfe3273cb7c1..06dec6f01f8d3937f5cde8387ea9fb7832f90635 100644 (file)
@@ -1629,17 +1629,18 @@ pub fn into_raw(self) -> *const 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) } }
     }
 }