diff --git a/crates/bevy_ecs/src/storage/blob_vec.rs b/crates/bevy_ecs/src/storage/blob_vec.rs index 80db14e3278363..7de3c0c8997d71 100644 --- a/crates/bevy_ecs/src/storage/blob_vec.rs +++ b/crates/bevy_ecs/src/storage/blob_vec.rs @@ -151,8 +151,20 @@ impl BlobVec { let ptr = self.get_unchecked_mut(index).promote().as_ptr(); self.len = 0; // Drop the old value, then write back, justifying the promotion + // If the drop impl for the old value panics then we run the drop impl for `value` too. if let Some(drop) = self.drop { + struct OnDrop(F); + impl Drop for OnDrop { + fn drop(&mut self) { + (self.0)(); + } + } + let value = value.as_ptr(); + let on_unwind = OnDrop(|| (drop)(OwningPtr::new(NonNull::new_unchecked(value)))); + (drop)(OwningPtr::new(NonNull::new_unchecked(ptr))); + + core::mem::forget(on_unwind); } std::ptr::copy_nonoverlapping::(value.as_ptr(), ptr, self.item_layout.size()); self.len = old_len; diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 71ee4c7a3716be..e65e8fba7f1b9f 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1631,6 +1631,7 @@ mod tests { DropLogItem::Create(0), DropLogItem::Create(1), DropLogItem::Drop(0), + DropLogItem::Drop(1), ] ); }