Skip to content

Commit 28223bd

Browse files
author
Lukas Markeffsky
committed
Rc/Arc: don't leak the allocation if drop panics
1 parent 5d8140d commit 28223bd

File tree

2 files changed

+17
-18
lines changed

2 files changed

+17
-18
lines changed

alloc/src/rc.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -2256,17 +2256,14 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> {
22562256
unsafe {
22572257
self.inner().dec_strong();
22582258
if self.inner().strong() == 0 {
2259-
// destroy the contained object
2260-
ptr::drop_in_place(Self::get_mut_unchecked(self));
2261-
2262-
// remove the implicit "strong weak" pointer now that we've
2263-
// destroyed the contents.
2264-
self.inner().dec_weak();
2265-
2266-
if self.inner().weak() == 0 {
2267-
self.alloc
2268-
.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()));
2269-
}
2259+
// Reconstruct the "strong weak" pointer and drop it when this
2260+
// variable goes out of scope. This ensures that the memory is
2261+
// deallocated even if the destructor of `T` panics.
2262+
let _weak = Weak { ptr: self.ptr, alloc: &self.alloc };
2263+
2264+
// Destroy the contained object.
2265+
// We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed.
2266+
ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value);
22702267
}
22712268
}
22722269
}

alloc/src/sync.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -1872,15 +1872,17 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
18721872
// Non-inlined part of `drop`.
18731873
#[inline(never)]
18741874
unsafe fn drop_slow(&mut self) {
1875+
// Drop the weak ref collectively held by all strong references when this
1876+
// variable goes out of scope. This ensures that the memory is deallocated
1877+
// even if the destructor of `T` panics.
1878+
// Take a reference to `self.alloc` instead of cloning because 1. it'll last long
1879+
// enough, and 2. you should be able to drop `Arc`s with unclonable allocators
1880+
let _weak = Weak { ptr: self.ptr, alloc: &self.alloc };
1881+
18751882
// Destroy the data at this time, even though we must not free the box
18761883
// allocation itself (there might still be weak pointers lying around).
1877-
unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
1878-
1879-
// Drop the weak ref collectively held by all strong references
1880-
// Take a reference to `self.alloc` instead of cloning because 1. it'll
1881-
// last long enough, and 2. you should be able to drop `Arc`s with
1882-
// unclonable allocators
1883-
drop(Weak { ptr: self.ptr, alloc: &self.alloc });
1884+
// We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed.
1885+
unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) };
18841886
}
18851887

18861888
/// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to

0 commit comments

Comments
 (0)