Skip to content

Commit f96c246

Browse files
committed
Strenghten synchronization in Arc::is_unique
Previously, `is_unique` would not synchronize at all with a `drop` that returned early because it was not the last reference, leading to a data race. Fixes rust-lang#51780
1 parent 860d169 commit f96c246

File tree

1 file changed

+7
-6
lines changed

1 file changed

+7
-6
lines changed

Diff for: src/liballoc/sync.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -886,13 +886,14 @@ impl<T: ?Sized> Arc<T> {
886886
// holder.
887887
//
888888
// The acquire label here ensures a happens-before relationship with any
889-
// writes to `strong` prior to decrements of the `weak` count (via drop,
890-
// which uses Release).
889+
// writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
890+
// of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
891+
// weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
891892
if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
892-
// Due to the previous acquire read, this will observe any writes to
893-
// `strong` that were due to upgrading weak pointers; only strong
894-
// clones remain, which require that the strong count is > 1 anyway.
895-
let unique = self.inner().strong.load(Relaxed) == 1;
893+
// This needs to be an `Acquire` to synchronize with the decrement of the `strong`
894+
// counter in `drop` -- the only access that happens when any but the last reference
895+
// is being dropped.
896+
let unique = self.inner().strong.load(Acquire) == 1;
896897

897898
// The release write here synchronizes with a read in `downgrade`,
898899
// effectively preventing the above read of `strong` from happening

0 commit comments

Comments
 (0)