diff options
| author | bors <bors@rust-lang.org> | 2020-05-27 11:18:53 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-05-27 11:18:53 +0000 |
| commit | acfc5584018de3a9a431a17f0cc34e0bfaf4cdeb (patch) | |
| tree | bc831a62648379cfb43fba304bff233e2e4200f5 /src/liballoc | |
| parent | 783139bd8fc3b94fac9a1bf81bba2c506e8221b6 (diff) | |
| parent | e6353aac9d0365d6541bb7f33548fdeb988b6563 (diff) | |
| download | rust-acfc5584018de3a9a431a17f0cc34e0bfaf4cdeb.tar.gz rust-acfc5584018de3a9a431a17f0cc34e0bfaf4cdeb.zip | |
Auto merge of #72639 - Dylan-DPC:rollup-76upj51, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #72348 (Fix confusing error message for comma typo in multiline statement) - #72533 (Resolve UB in Arc/Weak interaction (2)) - #72548 (Add test for old compiler ICE when using `Borrow`) - #72606 (Small cell example update) - #72610 (Remove font-display settings) - #72626 (Add remark regarding DoubleEndedIterator) Failed merges: r? @ghost
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/sync.rs | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index b7be8042ea4..8a45715e89c 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -867,12 +867,10 @@ impl<T: ?Sized> Arc<T> { unsafe fn drop_slow(&mut self) { // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). - ptr::drop_in_place(&mut self.ptr.as_mut().data); + ptr::drop_in_place(Self::get_mut_unchecked(self)); - if self.inner().weak.fetch_sub(1, Release) == 1 { - acquire!(self.inner().weak); - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) - } + // Drop the weak ref collectively held by all strong references + drop(Weak { ptr: self.ptr }); } #[inline] @@ -1204,7 +1202,7 @@ impl<T: Clone> Arc<T> { // As with `get_mut()`, the unsafety is ok because our reference was // either unique to begin with, or became one upon cloning the contents. - unsafe { &mut this.ptr.as_mut().data } + unsafe { Self::get_mut_unchecked(this) } } } @@ -1280,7 +1278,9 @@ impl<T: ?Sized> Arc<T> { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - &mut this.ptr.as_mut().data + // We are careful to *not* create a reference covering the "count" fields, as + // this would alias with concurrent access to the reference counts (e.g. by `Weak`). + &mut (*this.ptr.as_ptr()).data } /// Determine whether this is the unique reference (including weak refs) to @@ -1571,6 +1571,13 @@ impl<T> Weak<T> { } } +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a atomic::AtomicUsize, + strong: &'a atomic::AtomicUsize, +} + impl<T: ?Sized> Weak<T> { /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying /// dropping of the inner value if successful. @@ -1678,8 +1685,18 @@ impl<T: ?Sized> Weak<T> { /// Returns `None` when the pointer is dangling and there is no allocated `ArcInner`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] - fn inner(&self) -> Option<&ArcInner<T>> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option<WeakInner<'_>> { + if is_dangling(self.ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Arc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } } /// Returns `true` if the two `Weak`s point to the same allocation (similar to |
