fix leak of slaps with dropped payload

This commit is contained in:
Bennet Bleßmann
2024-07-07 15:51:22 +02:00
parent 689632b51c
commit 5d03be4b09
2 changed files with 27 additions and 6 deletions

View File

@@ -197,6 +197,7 @@ pub enum ArenaHeaderTag {
} }
#[bitfield] #[bitfield]
#[repr(align(8))]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct ArenaHeader { pub struct ArenaHeader {
#[allow(dead_code)] #[allow(dead_code)]
@@ -590,7 +591,16 @@ impl ArenaAllocated for LiveLoadState {
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) { unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) }; let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) };
unsafe { ManuallyDrop::drop(&mut slab.payload) };
match slab.tag() {
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
unsafe { ManuallyDrop::drop(&mut slab.payload) };
}
ArenaHeaderTag::Dropped => {}
_ => {
unreachable!()
}
}
drop(slab); drop(slab);
} }
} }
@@ -710,6 +720,7 @@ impl IndexPtrSlab {
let untyped_arena = UntypedArenaSlab { let untyped_arena = UntypedArenaSlab {
// safety: pointer from Box::into_raw is never null // safety: pointer from Box::into_raw is never null
slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) }, slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
tag: <IndexPtr as ArenaAllocated>::tag(),
}; };
(allocated_ptr, untyped_arena) (allocated_ptr, untyped_arena)
@@ -747,20 +758,21 @@ impl<T: ?Sized + ArenaAllocated> TypedAllocSlab<T> {
UntypedArenaSlab { UntypedArenaSlab {
// safety: pointer from Box::into_raw is never null // safety: pointer from Box::into_raw is never null
slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) }, slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
tag: T::tag(),
}, },
) )
} }
} }
#[derive(Debug)] #[derive(Debug)]
#[repr(transparent)]
pub struct UntypedArenaSlab { pub struct UntypedArenaSlab {
slab: NonNull<AllocSlab>, slab: NonNull<AllocSlab>,
tag: ArenaHeaderTag,
} }
impl Drop for UntypedArenaSlab { impl Drop for UntypedArenaSlab {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { drop_slab_in_place(self.slab) }; unsafe { drop_slab_in_place(self.slab, self.tag) };
} }
} }
@@ -784,14 +796,14 @@ impl Arena {
} }
} }
unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>) { unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
macro_rules! drop_typed_slab_in_place { macro_rules! drop_typed_slab_in_place {
($payload: ty, $value: expr) => { ($payload: ty, $value: expr) => {
<$payload as ArenaAllocated>::dealloc($value.cast::<TypedAllocSlab<$payload>>()) <$payload as ArenaAllocated>::dealloc($value.cast::<TypedAllocSlab<$payload>>())
}; };
} }
match (unsafe { value.as_ref() }).header.tag() { match tag {
ArenaHeaderTag::Integer => { ArenaHeaderTag::Integer => {
drop_typed_slab_in_place!(Integer, value); drop_typed_slab_in_place!(Integer, value);
} }

View File

@@ -470,7 +470,16 @@ macro_rules! arena_allocated_impl_for_stream {
unsafe fn dealloc(ptr: std::ptr::NonNull<TypedAllocSlab<Self>>) { unsafe fn dealloc(ptr: std::ptr::NonNull<TypedAllocSlab<Self>>) {
let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) }; let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) };
unsafe { std::mem::ManuallyDrop::drop(slab.payload()) };
match slab.tag() {
ArenaHeaderTag::$stream_tag => {
unsafe { std::mem::ManuallyDrop::drop(slab.payload()) };
}
ArenaHeaderTag::Dropped => {}
_ => {
unreachable!()
}
}
drop(slab); drop(slab);
} }
} }