@@ -829,8 +829,8 @@ impl<T: ?Sized> Rc<T> {
829829 let offset = unsafe { data_offset ( ptr) } ;
830830
831831 // Reverse the offset to find the original RcBox.
832- let fake_ptr = ptr as * mut RcBox < T > ;
833- let rc_ptr = unsafe { set_data_ptr ( fake_ptr , ( ptr as * mut u8 ) . offset ( -offset) ) } ;
832+ let rc_ptr =
833+ unsafe { ( ptr as * mut RcBox < T > ) . set_ptr_value ( ( ptr as * mut u8 ) . offset ( -offset) ) } ;
834834
835835 unsafe { Self :: from_ptr ( rc_ptr) }
836836 }
@@ -850,7 +850,7 @@ impl<T: ?Sized> Rc<T> {
850850 pub fn downgrade ( this : & Self ) -> Weak < T > {
851851 this. inner ( ) . inc_weak ( ) ;
852852 // Make sure we do not create a dangling Weak
853- debug_assert ! ( !is_dangling( this. ptr) ) ;
853+ debug_assert ! ( !is_dangling( this. ptr. as_ptr ( ) ) ) ;
854854 Weak { ptr : this. ptr }
855855 }
856856
@@ -1164,7 +1164,7 @@ impl<T: ?Sized> Rc<T> {
11641164 Self :: allocate_for_layout (
11651165 Layout :: for_value ( & * ptr) ,
11661166 |layout| Global . allocate ( layout) ,
1167- |mem| set_data_ptr ( ptr as * mut T , mem ) as * mut RcBox < T > ,
1167+ |mem| ( ptr as * mut RcBox < T > ) . set_ptr_value ( mem ) ,
11681168 )
11691169 }
11701170 }
@@ -1203,20 +1203,7 @@ impl<T> Rc<[T]> {
12031203 )
12041204 }
12051205 }
1206- }
1207-
1208- /// Sets the data pointer of a `?Sized` raw pointer.
1209- ///
1210- /// For a slice/trait object, this sets the `data` field and leaves the rest
1211- /// unchanged. For a sized raw pointer, this simply sets the pointer.
1212- unsafe fn set_data_ptr < T : ?Sized , U > ( mut ptr : * mut T , data : * mut U ) -> * mut T {
1213- unsafe {
1214- ptr:: write ( & mut ptr as * mut _ as * mut * mut u8 , data as * mut u8 ) ;
1215- }
1216- ptr
1217- }
12181206
1219- impl < T > Rc < [ T ] > {
12201207 /// Copy elements from slice into newly allocated Rc<\[T\]>
12211208 ///
12221209 /// Unsafe because the caller must either take ownership or bind `T: Copy`
@@ -1860,8 +1847,8 @@ impl<T> Weak<T> {
18601847 }
18611848}
18621849
1863- pub ( crate ) fn is_dangling < T : ?Sized > ( ptr : NonNull < T > ) -> bool {
1864- let address = ptr. as_ptr ( ) as * mut ( ) as usize ;
1850+ pub ( crate ) fn is_dangling < T : ?Sized > ( ptr : * mut T ) -> bool {
1851+ let address = ptr as * mut ( ) as usize ;
18651852 address == usize:: MAX
18661853}
18671854
@@ -1872,7 +1859,7 @@ struct WeakInner<'a> {
18721859 strong : & ' a Cell < usize > ,
18731860}
18741861
1875- impl < T > Weak < T > {
1862+ impl < T : ? Sized > Weak < T > {
18761863 /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
18771864 ///
18781865 /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1902,15 +1889,15 @@ impl<T> Weak<T> {
19021889 pub fn as_ptr ( & self ) -> * const T {
19031890 let ptr: * mut RcBox < T > = NonNull :: as_ptr ( self . ptr ) ;
19041891
1905- // SAFETY: we must offset the pointer manually, and said pointer may be
1906- // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
1907- // because we know that a pointer to unsized T was derived from a real
1908- // unsized T, as dangling weaks are only created for sized T. wrapping_offset
1909- // is used so that we can use the same code path for the non-dangling
1910- // unsized case and the potentially dangling sized case .
1911- unsafe {
1912- let offset = data_offset ( ptr as * mut T ) ;
1913- set_data_ptr ( ptr as * mut T , ( ptr as * mut u8 ) . wrapping_offset ( offset ) )
1892+ if is_dangling ( ptr ) {
1893+ // If the pointer is dangling, we return the sentinel directly. This cannot be
1894+ // a valid payload address, as the payload is at least as aligned as RcBox (usize).
1895+ ptr as * const T
1896+ } else {
1897+ // SAFETY: if is_dangling returns false, then the pointer is dereferencable .
1898+ // The payload may be dropped at this point, and we have to maintain provenance,
1899+ // so use raw pointer manipulation.
1900+ unsafe { & raw const ( * ptr ) . value }
19141901 }
19151902 }
19161903
@@ -1992,22 +1979,24 @@ impl<T> Weak<T> {
19921979 /// [`new`]: Weak::new
19931980 #[ stable( feature = "weak_into_raw" , since = "1.45.0" ) ]
19941981 pub unsafe fn from_raw ( ptr : * const T ) -> Self {
1995- // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
19961982 // See Weak::as_ptr for context on how the input pointer is derived.
1997- let offset = unsafe { data_offset ( ptr) } ;
19981983
1999- // Reverse the offset to find the original RcBox.
2000- // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized).
2001- let ptr = unsafe {
2002- set_data_ptr ( ptr as * mut RcBox < T > , ( ptr as * mut u8 ) . wrapping_offset ( -offset) )
1984+ let ptr = if is_dangling ( ptr as * mut T ) {
1985+ // This is a dangling Weak.
1986+ ptr as * mut RcBox < T >
1987+ } else {
1988+ // Otherwise, we're guaranteed the pointer came from a nondangling Weak.
1989+ // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
1990+ let offset = unsafe { data_offset ( ptr) } ;
1991+ // Thus, we reverse the offset to get the whole RcBox.
1992+ // SAFETY: the pointer originated from a Weak, so this offset is safe.
1993+ unsafe { ( ptr as * mut RcBox < T > ) . set_ptr_value ( ( ptr as * mut u8 ) . offset ( -offset) ) }
20031994 } ;
20041995
20051996 // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
20061997 Weak { ptr : unsafe { NonNull :: new_unchecked ( ptr) } }
20071998 }
2008- }
20091999
2010- impl < T : ?Sized > Weak < T > {
20112000 /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
20122001 /// dropping of the inner value if successful.
20132002 ///
@@ -2070,7 +2059,7 @@ impl<T: ?Sized> Weak<T> {
20702059 /// (i.e., when this `Weak` was created by `Weak::new`).
20712060 #[ inline]
20722061 fn inner ( & self ) -> Option < WeakInner < ' _ > > {
2073- if is_dangling ( self . ptr ) {
2062+ if is_dangling ( self . ptr . as_ptr ( ) ) {
20742063 None
20752064 } else {
20762065 // We are careful to *not* create a reference covering the "data" field, as
@@ -2325,21 +2314,19 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
23252314#[ stable( feature = "pin" , since = "1.33.0" ) ]
23262315impl < T : ?Sized > Unpin for Rc < T > { }
23272316
2328- /// Get the offset within an `RcBox` for
2329- /// a payload of type described by a pointer.
2317+ /// Get the offset within an `RcBox` for the payload behind a pointer.
23302318///
23312319/// # Safety
23322320///
2333- /// This has the same safety requirements as `align_of_val_raw`. In effect:
2334- ///
2335- /// - This function is safe for any argument if `T` is sized, and
2336- /// - if `T` is unsized, the pointer must have appropriate pointer metadata
2337- /// acquired from the real instance that you are getting this offset for.
2321+ /// The pointer must point to (and have valid metadata for) a previously
2322+ /// valid instance of T, but the T is allowed to be dropped.
23382323unsafe fn data_offset < T : ?Sized > ( ptr : * const T ) -> isize {
2339- // Align the unsized value to the end of the `RcBox`.
2340- // Because it is ?Sized, it will always be the last field in memory.
2341- // Note: This is a detail of the current implementation of the compiler,
2342- // and is not a guaranteed language detail. Do not rely on it outside of std.
2324+ // Align the unsized value to the end of the RcBox.
2325+ // Because RcBox is repr(C), it will always be the last field in memory.
2326+ // SAFETY: since the only unsized types possible are slices, trait objects,
2327+ // and extern types, the input safety requirement is currently enough to
2328+ // satisfy the requirements of align_of_val_raw; this is an implementation
2329+ // detail of the language that may not be relied upon outside of std.
23432330 unsafe { data_offset_align ( align_of_val_raw ( ptr) ) }
23442331}
23452332
0 commit comments