diff options
| author | bors <bors@rust-lang.org> | 2024-10-29 16:26:00 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-10-29 16:26:00 +0000 |
| commit | e473783d90e2289b8a97575fa60d6315f0a318eb (patch) | |
| tree | 55e21dc88822ef4f452ba8aebd6d45e5692a9aab /library/alloc/src | |
| parent | 2dece5bb62f234f5622a08289c5a3d1555cd7843 (diff) | |
| parent | 02ee6395fd4c7416691323415f575f65918e51f2 (diff) | |
| download | rust-e473783d90e2289b8a97575fa60d6315f0a318eb.tar.gz rust-e473783d90e2289b8a97575fa60d6315f0a318eb.zip | |
Auto merge of #132231 - lukas-code:rc-plug-leaks, r=tgross35
Rc/Arc: don't leak the allocation if drop panics Currently, when the last `Rc<T>` or `Arc<T>` is dropped and the destructor of `T` panics, the allocation will be leaked. This leak is unnecessary since the data cannot be (safely) accessed again and `Box` already deallocates in this case, so let's do the same for `Rc` and `Arc`, too.
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/rc.rs | 28 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 16 |
2 files changed, 26 insertions, 18 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 9fdd51ce331..fc8646e96d9 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -376,6 +376,21 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { unsafe fn from_ptr_in(ptr: *mut RcInner<T>, alloc: A) -> Self { unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Reconstruct the "strong weak" pointer and drop it when this + // variable goes out of scope. This ensures that the memory is + // deallocated even if the destructor of `T` panics. + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + + // Destroy the contained object. + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { + ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); + } + } } impl<T> Rc<T> { @@ -2252,21 +2267,12 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> { /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" /// ``` + #[inline] fn drop(&mut self) { unsafe { self.inner().dec_strong(); if self.inner().strong() == 0 { - // destroy the contained object - ptr::drop_in_place(Self::get_mut_unchecked(self)); - - // remove the implicit "strong weak" pointer now that we've - // destroyed the contents. - self.inner().dec_weak(); - - if self.inner().weak() == 0 { - self.alloc - .deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); - } + self.drop_slow(); } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 15a1b0f2834..98a2fe24257 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1872,15 +1872,17 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { + // Drop the weak ref collectively held by all strong references when this + // variable goes out of scope. This ensures that the memory is deallocated + // even if the destructor of `T` panics. + // Take a reference to `self.alloc` instead of cloning because 1. it'll last long + // enough, and 2. you should be able to drop `Arc`s with unclonable allocators + let _weak = Weak { ptr: self.ptr, alloc: &self.alloc }; + // Destroy the data at this time, even though we must not free the box // allocation itself (there might still be weak pointers lying around). - unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) }; - - // Drop the weak ref collectively held by all strong references - // Take a reference to `self.alloc` instead of cloning because 1. it'll - // last long enough, and 2. you should be able to drop `Arc`s with - // unclonable allocators - drop(Weak { ptr: self.ptr, alloc: &self.alloc }); + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) }; } /// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to |
