@@ -43,9 +43,6 @@ use vec::Vec;
43
43
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
44
44
const MAX_REFCOUNT : usize = ( isize:: MAX ) as usize ;
45
45
46
- /// A sentinel value that is used for the pointer of `Weak::new()`.
47
- const WEAK_EMPTY : usize = 1 ;
48
-
49
46
/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically
50
47
/// Reference Counted'.
51
48
///
@@ -239,9 +236,9 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
239
236
#[ stable( feature = "arc_weak" , since = "1.4.0" ) ]
240
237
pub struct Weak < T : ?Sized > {
241
238
// 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.
245
242
ptr : NonNull < ArcInner < T > > ,
246
243
}
247
244
@@ -1035,14 +1032,18 @@ impl<T> Weak<T> {
1035
1032
/// ```
1036
1033
#[ stable( feature = "downgraded_weak" , since = "1.10.0" ) ]
1037
1034
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 ( ) ,
1042
1037
}
1043
1038
}
1044
1039
}
1045
1040
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
+
1046
1047
impl < T : ?Sized > Weak < T > {
1047
1048
/// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending
1048
1049
/// the lifetime of the value if successful.
@@ -1074,11 +1075,7 @@ impl<T: ?Sized> Weak<T> {
1074
1075
pub fn upgrade ( & self ) -> Option < Arc < T > > {
1075
1076
// We use a CAS loop to increment the strong count instead of a
1076
1077
// 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 ( ) ?;
1082
1079
1083
1080
// Relaxed load because any write of 0 that we can observe
1084
1081
// leaves the field in a permanently zero state (so a
@@ -1109,6 +1106,17 @@ impl<T: ?Sized> Weak<T> {
1109
1106
}
1110
1107
}
1111
1108
}
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
+ }
1112
1120
}
1113
1121
1114
1122
#[ stable( feature = "arc_weak" , since = "1.4.0" ) ]
@@ -1126,10 +1134,10 @@ impl<T: ?Sized> Clone for Weak<T> {
1126
1134
/// ```
1127
1135
#[ inline]
1128
1136
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
1131
1139
} else {
1132
- unsafe { self . ptr . as_ref ( ) }
1140
+ return Weak { ptr : self . ptr } ;
1133
1141
} ;
1134
1142
// See comments in Arc::clone() for why this is relaxed. This can use a
1135
1143
// fetch_add (ignoring the lock) because the weak count is only locked
@@ -1204,10 +1212,10 @@ impl<T: ?Sized> Drop for Weak<T> {
1204
1212
// weak count can only be locked if there was precisely one weak ref,
1205
1213
// meaning that drop could only subsequently run ON that remaining weak
1206
1214
// 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
1209
1217
} else {
1210
- unsafe { self . ptr . as_ref ( ) }
1218
+ return
1211
1219
} ;
1212
1220
1213
1221
if inner. weak . fetch_sub ( 1 , Release ) == 1 {
0 commit comments