@@ -43,9 +43,6 @@ use vec::Vec;
4343/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
4444const MAX_REFCOUNT : usize = ( isize:: MAX ) as usize ;
4545
46- /// A sentinel value that is used for the pointer of `Weak::new()`.
47- const WEAK_EMPTY : usize = 1 ;
48-
4946/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically
5047/// Reference Counted'.
5148///
@@ -239,9 +236,9 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
239236#[ stable( feature = "arc_weak" , since = "1.4.0" ) ]
240237pub struct Weak < T : ?Sized > {
241238 // This is a `NonNull` to allow optimizing the size of this type in enums,
242- // but it is actually not truly "non-null". A `Weak::new()` will set this
243- // to a sentinel value, instead of needing to allocate some space in the
244- // heap.
239+ // but it is not necessarily a valid pointer.
240+ // `Weak::new` sets this to a dangling pointer so that it doesn’t need
241+ // to allocate space on the heap.
245242 ptr : NonNull < ArcInner < T > > ,
246243}
247244
@@ -1035,14 +1032,18 @@ impl<T> Weak<T> {
10351032 /// ```
10361033 #[ stable( feature = "downgraded_weak" , since = "1.10.0" ) ]
10371034 pub fn new ( ) -> Weak < T > {
1038- unsafe {
1039- Weak {
1040- ptr : NonNull :: new_unchecked ( WEAK_EMPTY as * mut _ ) ,
1041- }
1035+ Weak {
1036+ ptr : NonNull :: dangling ( ) ,
10421037 }
10431038 }
10441039}
10451040
1041+ fn is_dangling < T : ?Sized > ( ptr : NonNull < T > ) -> bool {
1042+ let address = ptr. as_ptr ( ) as * mut ( ) as usize ;
1043+ let align = align_of_val ( unsafe { ptr. as_ref ( ) } ) ;
1044+ address == align
1045+ }
1046+
10461047impl < T : ?Sized > Weak < T > {
10471048 /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending
10481049 /// the lifetime of the value if successful.
@@ -1074,11 +1075,7 @@ impl<T: ?Sized> Weak<T> {
10741075 pub fn upgrade ( & self ) -> Option < Arc < T > > {
10751076 // We use a CAS loop to increment the strong count instead of a
10761077 // fetch_add because once the count hits 0 it must never be above 0.
1077- let inner = if self . ptr . as_ptr ( ) as * const u8 as usize == WEAK_EMPTY {
1078- return None ;
1079- } else {
1080- unsafe { self . ptr . as_ref ( ) }
1081- } ;
1078+ let inner = self . inner ( ) ?;
10821079
10831080 // Relaxed load because any write of 0 that we can observe
10841081 // leaves the field in a permanently zero state (so a
@@ -1109,6 +1106,17 @@ impl<T: ?Sized> Weak<T> {
11091106 }
11101107 }
11111108 }
1109+
1110+ /// Return `None` when the pointer is dangling and there is no allocated `ArcInner`,
1111+ /// i.e. this `Weak` was created by `Weak::new`
1112+ #[ inline]
1113+ fn inner ( & self ) -> Option < & ArcInner < T > > {
1114+ if is_dangling ( self . ptr ) {
1115+ None
1116+ } else {
1117+ Some ( unsafe { self . ptr . as_ref ( ) } )
1118+ }
1119+ }
11121120}
11131121
11141122#[ stable( feature = "arc_weak" , since = "1.4.0" ) ]
@@ -1126,10 +1134,10 @@ impl<T: ?Sized> Clone for Weak<T> {
11261134 /// ```
11271135 #[ inline]
11281136 fn clone ( & self ) -> Weak < T > {
1129- let inner = if self . ptr . as_ptr ( ) as * const u8 as usize == WEAK_EMPTY {
1130- return Weak { ptr : self . ptr } ;
1137+ let inner = if let Some ( inner ) = self . inner ( ) {
1138+ inner
11311139 } else {
1132- unsafe { self . ptr . as_ref ( ) }
1140+ return Weak { ptr : self . ptr } ;
11331141 } ;
11341142 // See comments in Arc::clone() for why this is relaxed. This can use a
11351143 // fetch_add (ignoring the lock) because the weak count is only locked
@@ -1204,10 +1212,10 @@ impl<T: ?Sized> Drop for Weak<T> {
12041212 // weak count can only be locked if there was precisely one weak ref,
12051213 // meaning that drop could only subsequently run ON that remaining weak
12061214 // ref, which can only happen after the lock is released.
1207- let inner = if self . ptr . as_ptr ( ) as * const u8 as usize == WEAK_EMPTY {
1208- return ;
1215+ let inner = if let Some ( inner ) = self . inner ( ) {
1216+ inner
12091217 } else {
1210- unsafe { self . ptr . as_ref ( ) }
1218+ return
12111219 } ;
12121220
12131221 if inner. weak . fetch_sub ( 1 , Release ) == 1 {
0 commit comments