From ae9da68b52f52f3e702cdf2ef66f3509d0f6477c Mon Sep 17 00:00:00 2001 From: David Roundy Date: Sun, 18 Oct 2026 13:40:43 -0700 Subject: [PATCH] Handle allocation failure and zero-sized types pre_push wrote through the pointer returned by alloc without checking for null, so an allocation failure was undefined behavior. It now calls handle_alloc_error. For a zero-sized T the bin layouts have size zero, and calling alloc or dealloc with a zero-size layout is undefined behavior (Miri reports it). We now use a dangling pointer for those bins and never free it. Co-Authored-By: Claude Opus 5.5 --- src/lib.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f9834a2..0501a19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,7 +146,17 @@ impl AppendOnlyVec { // is determined in the self.layout method, which needs to be // consistent with the indices function. let layout = self.layout(array); - let ptr = unsafe { std::alloc::alloc(layout) } as *mut T; + let ptr = if layout.size() == 0 { + // Zero-sized types need no memory, and allocating a + // zero-sized layout is undefined behavior. + std::ptr::NonNull::::dangling().as_ptr() + } else { + let ptr = unsafe { std::alloc::alloc(layout) } as *mut T; + if ptr.is_null() { + std::alloc::handle_alloc_error(layout); + } + ptr + }; unsafe { *self.data[array as usize].get() = ptr; } @@ -343,7 +353,10 @@ impl Drop for AppendOnlyVec { let ptr = unsafe { *self.data[array as usize].get() }; if !ptr.is_null() { let layout = self.layout(array); - unsafe { std::alloc::dealloc(ptr as *mut u8, layout) }; + // Zero-sized types were never allocated (see `pre_push`). + if layout.size() != 0 { + unsafe { std::alloc::dealloc(ptr as *mut u8, layout) }; + } } else { break; } @@ -526,3 +539,14 @@ fn test_push_mut() { } assert_eq!(v.len(), 1024); } + +#[test] +fn test_zero_sized() { + let v = AppendOnlyVec::<()>::new(); + for _ in 0..1024 { + v.push(()); + } + assert_eq!(v.len(), 1024); + assert_eq!(v.iter().count(), 1024); + assert_eq!(v.into_vec().len(), 1024); +}