@@ -1862,7 +1862,7 @@ struct WeakInner<'a> {
1862
1862
strong : & ' a Cell < usize > ,
1863
1863
}
1864
1864
1865
- impl < T > Weak < T > {
1865
+ impl < T : ? Sized > Weak < T > {
1866
1866
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
1867
1867
///
1868
1868
/// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1892,15 +1892,17 @@ impl<T> Weak<T> {
1892
1892
pub fn as_ptr ( & self ) -> * const T {
1893
1893
let ptr: * mut RcBox < T > = NonNull :: as_ptr ( self . ptr ) ;
1894
1894
1895
- // SAFETY: we must offset the pointer manually, and said pointer may be
1896
- // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
1897
- // because we know that a pointer to unsized T was derived from a real
1898
- // unsized T, as dangling weaks are only created for sized T. wrapping_offset
1899
- // is used so that we can use the same code path for the non-dangling
1900
- // unsized case and the potentially dangling sized case.
1901
- unsafe {
1902
- let offset = data_offset ( ptr as * mut T ) ;
1903
- set_data_ptr ( ptr as * mut T , ( ptr as * mut u8 ) . wrapping_offset ( offset) )
1895
+ if is_dangling ( self . ptr ) {
1896
+ // If the pointer is dangling, we return a null pointer as the dangling sentinel.
1897
+ // We can't return the usize::MAX sentinel, as that could valid if T is ZST.
1898
+ // SAFETY: we have to return a known sentinel here that cannot be produced for
1899
+ // a valid pointer, so that `from_raw` can reverse this transformation.
1900
+ ( ptr as * mut T ) . set_ptr_value ( ptr:: null_mut ( ) )
1901
+ } else {
1902
+ // SAFETY: If the pointer is not dangling, it describes to a valid allocation.
1903
+ // The payload may be dropped at this point, and we have to maintain provenance,
1904
+ // so use raw pointer manipulation.
1905
+ unsafe { & raw mut ( * ptr) . value }
1904
1906
}
1905
1907
}
1906
1908
@@ -1982,22 +1984,25 @@ impl<T> Weak<T> {
1982
1984
/// [`new`]: Weak::new
1983
1985
#[ stable( feature = "weak_into_raw" , since = "1.45.0" ) ]
1984
1986
pub unsafe fn from_raw ( ptr : * const T ) -> Self {
1985
- // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
1986
1987
// See Weak::as_ptr for context on how the input pointer is derived.
1987
- let offset = unsafe { data_offset ( ptr) } ;
1988
1988
1989
- // Reverse the offset to find the original RcBox.
1990
- // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized).
1991
- let ptr = unsafe {
1992
- set_data_ptr ( ptr as * mut RcBox < T > , ( ptr as * mut u8 ) . wrapping_offset ( -offset) )
1989
+ let ptr = if ptr. is_null ( ) {
1990
+ // If we get a null pointer, this is a dangling weak.
1991
+ // SAFETY: this is the same sentinel as used in Weak::new and is_dangling
1992
+ ( ptr as * mut RcBox < T > ) . set_ptr_value ( usize:: MAX as * mut _ )
1993
+ } else {
1994
+ // Otherwise, this describes a real allocation.
1995
+ // SAFETY: data_offset is safe to call, as ptr describes a real allocation.
1996
+ let offset = unsafe { data_offset ( ptr) } ;
1997
+ // Thus, we reverse the offset to get the whole RcBox.
1998
+ // SAFETY: the pointer originated from a Weak, so this offset is safe.
1999
+ unsafe { ( ptr as * mut RcBox < T > ) . set_ptr_value ( ( ptr as * mut u8 ) . offset ( -offset) ) }
1993
2000
} ;
1994
2001
1995
2002
// SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
1996
2003
Weak { ptr : unsafe { NonNull :: new_unchecked ( ptr) } }
1997
2004
}
1998
- }
1999
2005
2000
- impl < T : ?Sized > Weak < T > {
2001
2006
/// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
2002
2007
/// dropping of the inner value if successful.
2003
2008
///
0 commit comments