Skip to content

Commit 6e2c49f

Browse files
committed
Use an aligned dangling pointer in Weak::new, rather than address 1
1 parent e06c875 commit 6e2c49f

File tree

1 file changed

+29
-21
lines changed

1 file changed

+29
-21
lines changed

src/liballoc/sync.rs

+29-21
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ use vec::Vec;
4343
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
4444
const 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")]
240237
pub 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+
10461047
impl<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

Comments
 (0)