From 4a71a592819b6fe87377dd5f857218ed37dbf195 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 27 Oct 2024 17:48:15 +0100 Subject: Rc/Arc: don't leak the allocation if drop panics --- library/alloc/src/rc.rs | 19 ++++++++----------- library/alloc/src/sync.rs | 16 +++++++++------- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'library/alloc/src') diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 9fdd51ce331..52ec8237d83 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2256,17 +2256,14 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { 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())); - } + // 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. + ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); } } } 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 Arc { // 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 -- cgit 1.4.1-3-g733a5 From 02ee6395fd4c7416691323415f575f65918e51f2 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 28 Oct 2024 22:59:14 +0100 Subject: Rc destructor: tweak inlining --- library/alloc/src/rc.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'library/alloc/src') diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 52ec8237d83..fc8646e96d9 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -376,6 +376,21 @@ impl Rc { unsafe fn from_ptr_in(ptr: *mut RcInner, 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 Rc { @@ -2252,18 +2267,12 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { /// 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 { - // 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. - ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); + self.drop_slow(); } } } -- cgit 1.4.1-3-g733a5