Skip to content

Commit

Permalink
Strenghten synchronization in Arc::is_unique
Browse files Browse the repository at this point in the history
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
  • Loading branch information
RalfJung committed Jul 3, 2018
1 parent 860d169 commit f96c246
Showing 1 changed file with 7 additions and 6 deletions.
13 changes: 7 additions & 6 deletions src/liballoc/sync.rs
Expand Up @@ -886,13 +886,14 @@ impl<T: ?Sized> Arc<T> {
// holder.
//
// The acquire label here ensures a happens-before relationship with any
// writes to `strong` prior to decrements of the `weak` count (via drop,
// which uses Release).
// writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
// of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
// weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
// Due to the previous acquire read, this will observe any writes to
// `strong` that were due to upgrading weak pointers; only strong
// clones remain, which require that the strong count is > 1 anyway.
let unique = self.inner().strong.load(Relaxed) == 1;
// This needs to be an `Acquire` to synchronize with the decrement of the `strong`
// counter in `drop` -- the only access that happens when any but the last reference
// is being dropped.
let unique = self.inner().strong.load(Acquire) == 1;

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

0 comments on commit f96c246

Please sign in to comment.