Skip to content

Commit ce28b4d

Browse files
Deallocate ThinBox even if the value unwinds on drop
1 parent bb6e76d commit ce28b4d

File tree

1 file changed

+34
-13
lines changed

1 file changed

+34
-13
lines changed

library/alloc/src/boxed/thin.rs

+34-13
Original file line numberDiff line numberDiff line change
@@ -226,24 +226,45 @@ impl<H> WithHeader<H> {
226226
// - Assumes that either `value` can be dereferenced, or is the
227227
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
228228
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
229+
struct DropGuard<H> {
230+
ptr: NonNull<u8>,
231+
value_layout: Layout,
232+
_marker: PhantomData<H>,
233+
}
234+
235+
impl<H> Drop for DropGuard<H> {
236+
fn drop(&mut self) {
237+
unsafe {
238+
// SAFETY: Layout must have been computable if we're in drop
239+
let (layout, value_offset) =
240+
WithHeader::<H>::alloc_layout(self.value_layout).unwrap_unchecked();
241+
242+
// Note: Don't deallocate if the layout size is zero, because the pointer
243+
// didn't come from the allocator.
244+
if layout.size() != 0 {
245+
alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout);
246+
} else {
247+
debug_assert!(
248+
value_offset == 0
249+
&& mem::size_of::<H>() == 0
250+
&& self.value_layout.size() == 0
251+
);
252+
}
253+
}
254+
}
255+
}
256+
229257
unsafe {
230-
let value_layout = Layout::for_value_raw(value);
231-
// SAFETY: Layout must have been computable if we're in drop
232-
let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked();
258+
// `_guard` will deallocate the memory when dropped, even if `drop_in_place` unwinds.
259+
let _guard = DropGuard {
260+
ptr: self.0,
261+
value_layout: Layout::for_value_raw(value),
262+
_marker: PhantomData::<H>,
263+
};
233264

234265
// We only drop the value because the Pointee trait requires that the metadata is copy
235266
// aka trivially droppable.
236267
ptr::drop_in_place::<T>(value);
237-
238-
// Note: Don't deallocate if the layout size is zero, because the pointer
239-
// didn't come from the allocator.
240-
if layout.size() != 0 {
241-
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
242-
} else {
243-
debug_assert!(
244-
value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
245-
);
246-
}
247268
}
248269
}
249270

0 commit comments

Comments
 (0)