⚠️ AI-generated issue — requires human investigation before acting on it.
Summary
TempFdArrayIterator in src/collector.rs yields &'a T items where 'a is the lifetime of the buffer slice. Items sourced from file_vec (an owned AVec<u8> inside the iterator) are returned with the same 'a lifetime via an unsafe pointer cast, but file_vec is owned by the iterator — not by the 'a borrow. This is unsound: the compiler cannot enforce that references into file_vec do not outlive the iterator itself.
Location
src/collector.rs, lines 225–243:
impl<'a, T> Iterator for TempFdArrayIterator<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
// ...
let ts = unsafe {
std::slice::from_raw_parts(self.file_vec.as_ptr() as *const T, length)
};
// ts has lifetime 'self, but the trait says Item = &'a T
// the returned reference is coerced to 'a, which can outlive self
Some(&ts[self.index - self.buffer.len() - 1])
}
}
Impact
A caller that collects references from this iterator and then drops the iterator would hold dangling references into freed file_vec memory. The pattern iterator.collect::<Vec<_>>() or holding references across iterator advancement would trigger use-after-free.
In the current codebase, try_iter() is consumed immediately via for_each in the report builders, which is safe. But the unsoundness is latent: any future use that holds references across iterator steps or drops the iterator while retaining references is UB.
Expected behaviour
The iterator should either:
- Store
file_vec alongside items decoded from it (e.g., eagerly decode into a Vec<T> and iterate that), or
- Use a self-referential structure with appropriate lifetime bounds (e.g., pin the vec separately), or
- Return owned
T values rather than references.
The current design exposes a safe-looking iterator API backed by an unsafe lifetime lie.
Summary
TempFdArrayIteratorinsrc/collector.rsyields&'a Titems where'ais the lifetime of thebufferslice. Items sourced fromfile_vec(an ownedAVec<u8>inside the iterator) are returned with the same'alifetime via anunsafepointer cast, butfile_vecis owned by the iterator — not by the'aborrow. This is unsound: the compiler cannot enforce that references intofile_vecdo not outlive the iterator itself.Location
src/collector.rs, lines 225–243:Impact
A caller that collects references from this iterator and then drops the iterator would hold dangling references into freed
file_vecmemory. The patterniterator.collect::<Vec<_>>()or holding references across iterator advancement would trigger use-after-free.In the current codebase,
try_iter()is consumed immediately viafor_eachin the report builders, which is safe. But the unsoundness is latent: any future use that holds references across iterator steps or drops the iterator while retaining references is UB.Expected behaviour
The iterator should either:
file_vecalongside items decoded from it (e.g., eagerly decode into aVec<T>and iterate that), orTvalues rather than references.The current design exposes a safe-looking iterator API backed by an
unsafelifetime lie.