diff --git a/src/guard.rs b/src/guard.rs index b477a77..2264c0d 100644 --- a/src/guard.rs +++ b/src/guard.rs @@ -66,9 +66,14 @@ impl<'vec, T> ContentGuard<'vec, T> { pub fn take(&mut self) -> Vec { let old_erased = std::mem::replace(self.erased, (self.reerase)(Vec::new())); let erased_owner = ManuallyDrop::new(old_erased); - // SAFETY: The erased pointer, length, and capacity are valid for a Vec. - // ManuallyDrop prevents the old TypeErasedVec from double-freeing the allocation. - unsafe { erased_owner.parts.into_vec() } + + // SAFETY: ManuallyDrop prevents the old TypeErasedVec from running its + // destructor. This reads its uniquely owned descriptor exactly once. + let parts = unsafe { std::ptr::read(&raw const erased_owner.parts) }; + + // SAFETY: The erased pointer, length, and capacity are valid for Vec, + // and `parts` uniquely owns the allocation. + unsafe { parts.into_vec() } } /// Calls `function` with the underlying vector and then type-erases it again. diff --git a/src/lib.rs b/src/lib.rs index 4ee7e02..df7be45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -329,6 +329,6 @@ impl TypeErasedVec { impl Drop for TypeErasedVec { fn drop(&mut self) { // SAFETY: The correct drop vector executes the destructors and frees the allocation. - unsafe { (self.vtable.drop)(self.parts) }; + unsafe { (self.vtable.drop)(&mut self.parts) }; } } diff --git a/src/parts.rs b/src/parts.rs index d2ded08..ece5c50 100644 --- a/src/parts.rs +++ b/src/parts.rs @@ -1,7 +1,6 @@ use std::mem::ManuallyDrop; use std::ptr::NonNull; -#[derive(Clone, Copy)] pub(super) struct VecParts { pub(super) ptr: NonNull, pub(super) len: usize, diff --git a/src/vtable.rs b/src/vtable.rs index 1cf48a5..9b956e4 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -58,14 +58,18 @@ pub(super) struct TypeErasedVecVtable { /// Function pointer to clear the underlying capacity of its old elements pub(super) clear: unsafe fn(parts: &mut VecParts), /// Function pointer to the original type's drop logic. - pub(super) drop: unsafe fn(parts: VecParts), + pub(super) drop: unsafe fn(parts: &mut VecParts), } impl TypeErasedVecVtable { pub(super) fn new() -> Self { - unsafe fn drop_vec(parts: VecParts) { - // SAFETY: We reconstruct the Vec to let its Drop impl handle deallocation. - _ = unsafe { parts.into_vec::() }; + unsafe fn drop_vec(parts: &mut VecParts) { + let original_parts = std::mem::replace(parts, VecParts::from_vec(Vec::::new())); + + // SAFETY: The vtable selects T as the exact type that originally + // produced these uniquely owned raw parts. Reconstructing the Vec + // transfers that ownership to its Drop implementation. + _ = unsafe { original_parts.into_vec::() }; } unsafe fn clear_vec(parts: &mut VecParts) {