Skip to content

Unsound safe Clone implementation on ArrayType<T> executing unreachable_unchecked() #170

Description

@Manishearth

Note

This finding was identified during an agentic unsafe Rust code review performed by Gemini AI, followed by human review and verification.

The Issue

In generic-array v1, ArrayLength::ArrayType<T> is a public associated type defined on the public unsafe trait ArrayLength. For any given length N, N::ArrayType<T> resolves statically to internal container structs (GenericArrayImplEven<T, U> or GenericArrayImplOdd<T, U>). These internal struct types implement standard library Clone whenever T: Clone and U: Clone like so:

generic-array/src/lib.rs

Lines 364 to 379 in 778e6dd

impl<T: Clone, U: Clone> Clone for GenericArrayImplEven<T, U> {
#[inline(always)]
fn clone(&self) -> GenericArrayImplEven<T, U> {
// Clone is never called on the GenericArrayImpl types,
// as we use `self.map(clone)` elsewhere. This helps avoid
// extra codegen for recursive clones when they are never used.
unsafe { core::hint::unreachable_unchecked() }
}
}
impl<T: Clone, U: Clone> Clone for GenericArrayImplOdd<T, U> {
#[inline(always)]
fn clone(&self) -> GenericArrayImplOdd<T, U> {
unsafe { core::hint::unreachable_unchecked() }
}
}

The accompanying code comment asserts that Clone is never called on these internal types because GenericArray<T, N>::clone delegates to self.map(Clone::clone). However, because ArrayType<T> is a public associated type on a public trait, downstream crates can explicitly name and construct the type <N as ArrayLength>::ArrayType<T>.

Minimal Reproduction
use generic_array::ArrayLength;

fn main() {
    let arr = unsafe { std::mem::zeroed::<<typenum::U2 as ArrayLength>::ArrayType<u8>>() };
    let _cloned = arr.clone();
}
thread 'main' panicked at 'internal error: entered unreachable code'

Note

The full audit report below also contains additional minor findings (such as missing safety comments or undocumented FFI assumptions) that are probably worth fixing as well but not the primary goal of this issue. The audit report has not been human-reviewed, it may contain misleading claims.

Full Gemini Codebase Audit Report Appendix

Unsafe Rust Review: generic_array (v1)

Overall Safety Assessment

generic_array provides a statically allocated generic array structure GenericArray<T, N: ArrayLength>, allowing arrays to be parameterized by type-level unsigned integers (typenum::Unsigned). To bypass legacy compiler restrictions on generic array lengths, the crate constructs a recursive, binary-tree-like type hierarchy at compile time using internal container structs (GenericArrayImplEven and GenericArrayImplOdd). At runtime, these recursive structures are reinterpreted as contiguous memory buffers of size N * size_of::<T>() and alignment align_of::<T>(), functioning interchangeably with native Rust arrays [T; N].

Unsafe Surface & Density

The crate exhibits a substantial density of unsafe code across 11 source files, comprising over 90 distinct unsafe fn, unsafe trait, unsafe impl, or unsafe {} blocks. The core unsafe surface is concentrated in:

  • src/lib.rs (24 items): Core trait implementations (ArrayLength, Send, Sync, GenericSequence), raw slice extractions (as_slice, as_mut_slice), pointer transmutes (from_slice, from_array), and uninitialized memory assumptions (uninit, assume_init).
  • src/sequence.rs (22 items): Sequence manipulation traits (GenericSequence, Lengthen, Shorten, Split, Flatten, Unflatten) performing pointer arithmetic and type-punning transmutes across nested array layouts.
  • src/internal.rs (13 items): Incremental array construction and consumption wrappers (ArrayBuilder, IntrusiveArrayBuilder, ArrayConsumer, IntrusiveArrayConsumer) managing partial initialization and drop-on-panic invariants.
  • src/iter.rs (9 items): By-value iterator traversal (GenericArrayIter) utilizing raw pointer reads/writes and mem::forget.
  • src/hex.rs (5 items): SIMD hex encoding hooks and unchecked UTF-8 string conversions.
  • src/impl_alloc.rs & src/impl_serde.rs (5 items): Heap allocation lifecycles (Box, Vec) and visitor sequence building.
  • src/compat/ (8 items): Layout-preserving transmutes for interoperability with generic-array 0.14 and hybrid-array 0.4.

Soundness & Architectural Evaluation

Despite its central position in the Rust data-structure and cryptographic ecosystem, our rigorous audit grounded in authoritative Rust Reference semantics reveals that generic_array v1 (specifically v1.3.5) is Unsound and contains three severe Critical Findings:

  1. Unsound safe Clone trait implementations on publicly nameable associated types executing unreachable_unchecked().
  2. Fabrication of invalid slice references (&[T] / &mut [T]) over partially moved/uninitialized array elements during iterator drop and traversal.
  3. Unchecked alloc::alloc::alloc return values triggering null pointer dereferences (&mut *null) upon allocation failure.

Furthermore, the crate completely lacks formal // SAFETY: proof comments and # Safety docstrings across almost its entire codebase (88 distinct missing proof locations).

Critical Findings

1. Unsound Safe Trait Implementation (Clone) on Nameable Type Executing unreachable_unchecked() (src/lib.rs:370, src/lib.rs:377) 🔴 🤸

  • Severity: 🔴 High
  • Threat Vector: 🤸 Deliberate Contortion
  • Bug Type: Soundness Violation
  • Vulnerability Type: Soundness Violation / Safe-to-Unsafe Triggerable Undefined Behavior.
  • Description: ArrayLength::ArrayType<T> is a public associated type defined on the public unsafe trait ArrayLength. For any given length N, N::ArrayType<T> resolves statically to GenericArrayImplEven<T, U> or GenericArrayImplOdd<T, U>. In src/lib.rs:364 and 374, these internal struct types implement standard library Clone whenever T: Clone and U: Clone. However, their clone(&self) method bodies consist entirely of unsafe { core::hint::unreachable_unchecked() }. The authors included a comment stating that Clone is never called on these internal types because GenericArray<T, N>::clone(&self) delegates to self.map(Clone::clone). However, because ArrayType<T> is a public associated type on a public trait, downstream crates can explicitly name the type <N as ArrayLength>::ArrayType<T>. Furthermore, when the crate's const-default feature flag is enabled (as listed in package.metadata.docs.rs.features), GenericArrayImplEven and GenericArrayImplOdd implement ConstDefault. Consequently, 100% safe downstream code can construct an instance via let arr = <typenum::U2 as ArrayLength>::ArrayType<MyType>::DEFAULT and invoke arr.clone(). This compiles purely in safe Rust without warnings or unsafe blocks and immediately triggers unreachable_unchecked() at runtime. Even without const-default, exposing a public type implementing a safe trait (Clone) where invoking the trait method executes unreachable_unchecked() violates fundamental Rust soundness guarantees.

2. Invalid Slice Reference Fabrication on Partially Moved Arrays (src/iter.rs:21, 28, 59, 153, 213, src/internal.rs:283, 320) 🔴 🤦

  • Severity: 🔴 High
  • Threat Vector: 🤦 Accidental Misuse
  • Bug Type: Validity Invariant Breach
  • Vulnerability Type: Soundness Violation / Validity Invariant Breach.
  • Description: GenericArrayIter<T, N>, ArrayConsumer<T, N>, and IntrusiveArrayConsumer<T, N> encapsulate underlying array storage (e.g., ManuallyDrop<GenericArray<T, N>>). During iterator traversal (next(), nth(), map()), leading elements at indices [0..self.index] or trailing elements at [self.index_back..N] are consumed by value via ptr::read. Consequently, memory at those consumed indices becomes uninitialized or moved-out storage. However, whenever self.array.get_unchecked(...) or get_unchecked_mut(...) is invoked (in as_slice, as_mut_slice, next, nth, drop), resolving get_unchecked on GenericArray<T, N> forces auto-dereferencing via <GenericArray<T, N> as Deref>::deref or DerefMut::deref_mut. GenericArray::deref and deref_mut execute slice::from_raw_parts / from_raw_parts_mut spanning the entire N::USIZE element range (0..N). According to the Rust Reference (Behavior considered undefined: "Producing an invalid value... when a reference to value is created"), fabricating a safe reference &[T] or &mut [T] covering a contiguous buffer where some T elements are uninitialized or moved out immediately produces references to invalid values. Under Stacked Borrows and Tree Borrows formal aliasing models, this triggers Undefined Behavior.

3. Unchecked Allocator Return Value Leading to Null Pointer Dereference (src/impl_alloc.rs:177) 🔴 🤦

  • Severity: 🔴 High
  • Threat Vector: 🤦 Accidental Misuse
  • Bug Type: Null Pointer Dereference
  • Vulnerability Type: Null Pointer Dereference / Unchecked Allocation Failure.
  • Description: In GenericSequence::generate for Box<GenericArray<T, N>>, raw heap memory is allocated directly via alloc::alloc::alloc(Layout::new::<GenericArray<MaybeUninit<T>, N>>()). Unlike standard library collections (Vec, Box) which check for null pointers and invoke handle_alloc_error upon allocation failure, this crate omits return value validation entirely. On out-of-memory (OOM) or allocation failure, alloc::alloc::alloc returns a null pointer (null_mut()). The immediately subsequent line let mut builder = IntrusiveArrayBuilder::new(&mut *ptr) dereferences the null raw pointer (&mut *null) to construct a mutable reference &mut GenericArray<MaybeUninit<T>, N>. In Rust authoritative semantics and LLVM optimization rules, dereferencing a null pointer or fabricating a null reference is unconditional Undefined Behavior.

Fishy Findings

1. Memory Leak of Raw Heap Allocations on Generator Panics (src/impl_alloc.rs:185) 🟡 🤦

  • Severity: 🟡 Low
  • Threat Vector: 🤦 Accidental Misuse
  • Bug Type: Memory Leak
  • Observation: In Box<GenericArray<T, N>>::generate, raw heap storage is allocated via alloc::alloc::alloc and passed to IntrusiveArrayBuilder::new(&mut *ptr). A user-supplied closure f(i) is invoked sequentially to initialize array elements.
  • Analysis: If f(i) panics during initialization, IntrusiveArrayBuilder::drop correctly drops all initialized elements up to position. However, IntrusiveArrayBuilder does not own or free the underlying raw allocation pointer ptr. The raw pointer is only converted into an RAII-managed Box at the very end of the function (Box::from_raw). Therefore, any panic inside f permanently leaks the raw heap allocation buffer. While leaking memory during unwinding does not constitute Undefined Behavior in Rust, failing to wrap raw allocator returns in an RAII cleanup guard on error paths represents fragile low-level design.

2. Implicit Unsafe Operations via Missing #![deny(unsafe_op_in_unsafe_fn)] Enforcement 🟡 🤦

  • Severity: 🟡 Low
  • Threat Vector: 🤦 Accidental Misuse
  • Bug Type: Missing Lint Enforcement
  • Observation: The crate specifies Rust edition 2021 but omits #![deny(unsafe_op_in_unsafe_fn)].
  • Analysis: Across src/lib.rs, src/sequence.rs, and src/internal.rs, dozens of internal unsafe fn APIs perform raw pointer dereferences, union field accesses, and type-punning transmutes directly within their function bodies without delineating unsafe {} blocks. Omitting lexical unsafe {} containment within unsafe fn blurs proof boundaries and increases maintainer hazard during security auditing.

Missing Safety Comments

Across the crate, 88 distinct unsafe locations lack required // SAFETY: proof comments or # Safety docstrings. We enumerate every location below along with formal proof obligations.

Module src/lib.rs (24 locations) 🔴

  • src/lib.rs:274 (unsafe impl ArrayLength for UTerm): Missing // SAFETY: comment.
    • Proposed Proof: UTerm represents 0 elements; [T; 0] is a valid contiguous layout of 0 elements matching size_of::<[T; 0]>() == 0.
  • src/lib.rs:402 (unsafe impl ArrayLength for UInt<N, B0>): Missing // SAFETY: comment.
    • Proposed Proof: By structural induction, GenericArrayImplEven<T, U> contains [U; 2] and PhantomData, possessing exact size 2 * size_of::<U>() and alignment align_of::<T>() with zero internal padding.
  • src/lib.rs:410 (unsafe impl ArrayLength for UInt<N, B1>): Missing // SAFETY: comment.
    • Proposed Proof: GenericArrayImplOdd<T, U> contains [U; 2] and T, possessing exact size (2 * size_of::<U>() + size_of::<T>()) and alignment align_of::<T>() with zero internal padding.
  • src/lib.rs:537 (unsafe impl Send for GenericArray<T, N>): Missing // SAFETY: comment.
    • Proposed Proof: GenericArray<T, N> is transparent over N contiguous elements of T; ownership transfer across threads is sound iff T: Send.
  • src/lib.rs:538 (unsafe impl Sync for GenericArray<T, N>): Missing // SAFETY: comment.
    • Proposed Proof: Shared reference access across threads is sound iff T: Sync.
  • src/lib.rs:598 (unsafe impl GenericSequence for GenericArray<T, N>): Missing // SAFETY: comment.
    • Proposed Proof: GenericArray length matches N, and IntrusiveArrayBuilder ensures panic safety during generation.
  • src/lib.rs:610 (unsafe { ... } in GenericSequence::generate): Missing // SAFETY: comment.
    • Proposed Proof: MaybeUninit::uninit() is valid for uninitialized storage; IntrusiveArrayBuilder tracks element initialization and assumes init only after position == N.
  • src/lib.rs:639 (unsafe { ... } in inverted_zip): Missing // SAFETY: comment.
    • Proposed Proof: IntrusiveArrayConsumer tracks consumed elements and ensures remaining unread items drop if f panics; ptr::read moves elements out exactly once.
  • src/lib.rs:683 (unsafe { ... } in inverted_zip2): Missing // SAFETY: comment.
    • Proposed Proof: Identical proof obligation to inverted_zip.
  • src/lib.rs:726 (unsafe { ... } in FunctionalSequence::map): Missing // SAFETY: comment.
    • Proposed Proof: IntrusiveArrayConsumer wraps self to drop unconsumed elements on panic; each element is read exactly once via ptr::read.
  • src/lib.rs:786 (unsafe { slice::from_raw_parts(...) } in as_slice): Missing // SAFETY: comment.
    • Proposed Proof: self is a valid aligned reference spanning N * size_of::<T>() initialized bytes.
  • src/lib.rs:795 (unsafe { slice::from_raw_parts_mut(...) } in as_mut_slice): Missing // SAFETY: comment.
    • Proposed Proof: self is a valid exclusive mutable reference spanning N initialized elements.
  • src/lib.rs:812 (unsafe { &*(...) } in from_slice): Missing // SAFETY: comment.
    • Proposed Proof: Precondition slice.len() == N::USIZE ensures length equality; GenericArray<T, N> has identical memory layout to [T; N].
  • src/lib.rs:825 (unsafe { &*(...) } in try_from_slice): Missing // SAFETY: comment.
    • Proposed Proof: Identical layout and bounds verification proof to from_slice.
  • src/lib.rs:845 (unsafe { &mut *(...) } in from_mut_slice): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable reference cast is sound due to transparent layout and exact length assert.
  • src/lib.rs:881 (unsafe { ... } in chunks_from_slice): Missing // SAFETY: comment.
    • Proposed Proof: Division computes exact chunk count; slice pointers are aligned for GenericArray<T, N> due to matching element alignment align_of::<T>().
  • src/lib.rs:910 (unsafe { ... } in chunks_from_slice_mut): Missing // SAFETY: comment.
    • Proposed Proof: Identical alignment and non-overlapping mutable subslice division proof.
  • src/lib.rs:933 (unsafe { slice::from_raw_parts_mut(...) } in slice_from_chunks_mut): Missing // SAFETY: comment.
    • Proposed Proof: Total element count is slice.len() * N::USIZE; contiguous chunk slice memory is valid for underlying [T].
  • src/lib.rs:944 (unsafe { crate::const_transmute(...) } in from_array): Missing // SAFETY: comment.
    • Proposed Proof: [T; U] and GenericArray<T, N> have identical size, layout, and alignment where U == N::USIZE.
  • src/lib.rs:955 (unsafe { crate::const_transmute(...) } in into_array): Missing // SAFETY: comment.
    • Proposed Proof: Reverse transparent transmutation preserving size and validity invariants.
  • src/lib.rs:964 (unsafe { mem::transmute(...) } in from_chunks): Missing // SAFETY: comment.
    • Proposed Proof: Slice wide-pointer cast preserves length and pointer metadata; element layouts match exactly.
  • src/lib.rs:976 (unsafe { mem::transmute(...) } in from_chunks_mut): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable slice wide-pointer cast preserving metadata.
  • src/lib.rs:985 (unsafe { mem::transmute(...) } in into_chunks): Missing // SAFETY: comment.
    • Proposed Proof: Slice wide-pointer cast from GenericArray chunks to native array chunks.
  • src/lib.rs:997 (unsafe { mem::transmute(...) } in into_chunks_mut): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable slice wide-pointer cast.

Module src/arr.rs (2 locations) 🔴

  • src/arr.rs:33 (unsafe { $crate::const_transmute(arr) }): Missing // SAFETY: comment.
    • Proposed Proof: arr is an initialized native array of exact length N::USIZE; transparent layout transmutation is sound.
  • src/arr.rs:85 (unsafe { GenericArray::try_from_vec(vec).unwrap_unchecked() }): Missing // SAFETY: comment.
    • Proposed Proof: Macro construction ensures vec.len() == U == N::USIZE; fallible conversion is guaranteed to return Ok.

Module src/iter.rs (9 locations) 🔴

  • src/iter.rs:59 (unsafe { ptr::drop_in_place(...) } in Drop for GenericArrayIter): Missing // SAFETY: comment.
    • Proposed Proof: as_mut_slice() spans remaining unconsumed elements [index..index_back]; dropping them in place exactly once is sound.
  • src/iter.rs:71 (unsafe { ptr::read(&self.array) } in Clone for GenericArrayIter): Missing // SAFETY: comment.
    • Proposed Proof: Bitwise copy of container; aliasing double-frees are prevented by restricting returned index_back and ManuallyDrop.
  • src/iter.rs:75 (unsafe { ptr::write(dst, src.clone()) }): Missing // SAFETY: comment.
    • Proposed Proof: dst pointer is valid and unread in destination allocation.
  • src/iter.rs:93 (unsafe { Some(ptr::read(...)) } in next): Missing // SAFETY: comment.
    • Proposed Proof: self.index < self.index_back confirms element is alive and unread; moving out via read is sound.
  • src/iter.rs:108 (unsafe { ... } in fold): Missing // SAFETY: comment.
    • Proposed Proof: Remaining elements slice is valid; mem::forget prevents double-freeing consumed items upon completion.
  • src/iter.rs:153 (unsafe { ptr::drop_in_place(...) } in nth): Missing // SAFETY: comment.
    • Proposed Proof: Elements in [index..next_index] are alive; dropping them prior to advancing index is sound.
  • src/iter.rs:175 (unsafe { Some(ptr::read(...)) } in next_back): Missing // SAFETY: comment.
    • Proposed Proof: Decremented index_back >= index confirms element is alive.
  • src/iter.rs:186 (unsafe { ... } in rfold): Missing // SAFETY: comment.
    • Proposed Proof: Reverse fold traversal; mem::forget prevents double drops.
  • src/iter.rs:213 (unsafe { ptr::drop_in_place(...) } in nth_back): Missing // SAFETY: comment.
    • Proposed Proof: Elements in [next_back..index_back] are alive and unread.

Module src/sequence.rs (22 locations) 🔴

  • src/sequence.rs:48 (unsafe { ... } in GenericSequence::inverted_zip): Missing // SAFETY: comment.
    • Proposed Proof: IntrusiveArrayConsumer ensures panic safety; ptr::read extracts elements sequentially.
  • src/sequence.rs:83 (unsafe impl GenericSequence for &S): Missing // SAFETY: comment.
    • Proposed Proof: Shared reference sequence delegation preserves length and validity invariants.
  • src/sequence.rs:99 (unsafe impl GenericSequence for &mut S): Missing // SAFETY: comment.
    • Proposed Proof: Mutable reference sequence delegation.
  • src/sequence.rs:202 (unsafe impl Lengthen for GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Add1<N> length arithmetic is verified by typenum trait bounds.
  • src/sequence.rs:218 (unsafe { ... } in Lengthen::append): Missing // SAFETY: comment.
    • Proposed Proof: out_ptr spans uninitialized memory for N + 1 elements; writing self (N items) at offset 0 and last at offset N fully initializes Longer.
  • src/sequence.rs:235 (unsafe { ... } in Lengthen::prepend): Missing // SAFETY: comment.
    • Proposed Proof: Writing first at offset 0 and self at offset 1 fully initializes Longer.
  • src/sequence.rs:246 (unsafe impl Shorten for GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Sub1<N> length arithmetic verified by trait bounds.
  • src/sequence.rs:259 (unsafe { ... } in Shorten::pop_back): Missing // SAFETY: comment.
    • Proposed Proof: whole is in ManuallyDrop; reading first N - 1 elements as Shorter and element N - 1 as last partitions ownership cleanly.
  • src/sequence.rs:272 (unsafe { ... } in Shorten::pop_front): Missing // SAFETY: comment.
    • Proposed Proof: Reading element 0 as head and remaining N - 1 elements as tail partitions ownership cleanly.
  • src/sequence.rs:296 (unsafe impl Split for GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: N: Sub<K> ensures valid split indices; pointer reads partition array memory.
  • src/sequence.rs:595 (unsafe impl Flatten for GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Prod<N, M> equals exact total contiguous element count N * M.
  • src/sequence.rs:605 (unsafe { crate::const_transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Nested array GenericArray<GenericArray<T, N>, M> has exact size and layout equal to GenericArray<T, N * M>.
  • src/sequence.rs:609 (unsafe impl Flatten for &GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Shared reference pointer cast preserving metadata.
  • src/sequence.rs:619 (unsafe { mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Wide pointer cast between identical layouts.
  • src/sequence.rs:623 (unsafe impl Flatten for &mut GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable reference cast.
  • src/sequence.rs:633 (unsafe { mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable wide pointer cast.
  • src/sequence.rs:637 (unsafe impl Unflatten for GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Quot<NM, N> exact divisibility bounds verify total element equality.
  • src/sequence.rs:647 (unsafe { crate::const_transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Flat array reinterpreted as nested array chunks.
  • src/sequence.rs:651 (unsafe impl Unflatten for &GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Shared reference unflattening cast.
  • src/sequence.rs:661 (unsafe { mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Wide pointer unflattening cast.
  • src/sequence.rs:665 (unsafe impl Unflatten for &mut GenericArray): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable reference unflattening cast.
  • src/sequence.rs:675 (unsafe { mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable wide pointer unflattening cast.

Module src/hex.rs (5 locations) 🔴

  • src/hex.rs:24 (unsafe { core::hint::unreachable_unchecked() }): Missing // SAFETY: comment.
    • Proposed Proof: Caller guarantees dst.len() >= src.len() * 2; branch is unreachable.
  • src/hex.rs:48 (unsafe { faster_hex::hex_encode_upper(...).unwrap_unchecked() }): Missing // SAFETY: comment.
    • Proposed Proof: Buffer length check ensures faster_hex returns Ok.
  • src/hex.rs:49 (unsafe { faster_hex::hex_encode(...).unwrap_unchecked() }): Missing // SAFETY: comment.
    • Proposed Proof: Buffer length check ensures faster_hex returns Ok.
  • src/hex.rs:73 (unsafe { core::hint::unreachable_unchecked() }): Missing // SAFETY: comment.
    • Proposed Proof: max_bytes <= N::USIZE due to precision capping; branch is unreachable.
  • src/hex.rs:92 (unsafe { str::from_utf8_unchecked(...) }): Missing // SAFETY: comment.
    • Proposed Proof: Hex alphabet characters are ASCII (0-9a-fA-F), constituting valid UTF-8.

Module src/internal.rs (13 locations) 🔴

  • src/internal.rs:38 (pub unsafe fn extend(&mut self, ...)): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must guarantee iterator yields valid elements and position accurately tracks initialized items.
  • src/internal.rs:77 (pub unsafe fn iter_position(...)): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must increment position exactly for each initialized element written.
  • src/internal.rs:89 (pub unsafe fn assume_init(self) -> ...): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must guarantee self.is_full() holds.
  • src/internal.rs:100 (unsafe { ptr::drop_in_place(...) } in Drop for ArrayBuilder): Missing // SAFETY: comment.
    • Proposed Proof: Elements in [0..self.position] were initialized; dropping them in place is sound.
  • src/internal.rs:151 (pub unsafe fn extend(...) on IntrusiveArrayBuilder): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must ensure extend is called at most once per builder.
  • src/internal.rs:193 (pub unsafe fn iter_position(...) on IntrusiveArrayBuilder): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must increment position after giving ownership to dst.write.
  • src/internal.rs:202 (pub const unsafe fn finish(self)): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must guarantee self.is_full() holds prior to forgetting cleanup.
  • src/internal.rs:232 (pub unsafe fn array_assume_init(...)): Missing # Safety docstring and // SAFETY: comment on line 233.
    • Proposed Theorem: Precondition: All elements of array must be initialized.
  • src/internal.rs:239 (unsafe { ptr::drop_in_place(...) } in Drop for IntrusiveArrayBuilder): Missing // SAFETY: comment.
    • Proposed Proof: Elements [0..self.position] are initialized and dropped exactly once.
  • src/internal.rs:276 (pub unsafe fn iter_position(...) on ArrayConsumer): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must increment position for each element consumed by value.
  • src/internal.rs:283 (unsafe { ptr::drop_in_place(...) } in Drop for ArrayConsumer): Missing // SAFETY: comment.
    • Proposed Proof: Elements [self.position..N] remain unconsumed and valid for dropping.
  • src/internal.rs:313 (pub unsafe fn iter_position(...) on IntrusiveArrayConsumer): Missing # Safety docstring.
    • Proposed Theorem: Precondition: Caller must increment position for each element consumed.
  • src/internal.rs:320 (unsafe { ptr::drop_in_place(...) } in Drop for IntrusiveArrayConsumer): Missing // SAFETY: comment.
    • Proposed Proof: Remaining unconsumed elements [self.position..N] are dropped exactly once.

Module src/compat/generic_array_0_14.rs (4 locations) 🔴

  • src/compat/generic_array_0_14.rs:43 (unsafe { core::mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: GenericArray 0.14 and v1 share identical transparent representation over [T; N].
  • src/compat/generic_array_0_14.rs:52 (unsafe { core::mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable reference cast between identical layouts.
  • src/compat/generic_array_0_14.rs:58 (unsafe { crate::const_transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Value transmutation between identical layouts.
  • src/compat/generic_array_0_14.rs:64 (unsafe { crate::const_transmute(value) }): Missing // SAFETY: comment.
    • Proposed Proof: Value transmutation from 0.14 to v1.

Module src/compat/hybrid_array_0_4.rs (4 locations) 🔴

  • src/compat/hybrid_array_0_4.rs:55 (unsafe { core::mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: hybrid_array_0_4::Array is a #[repr(transparent)] wrapper over GenericArray; layouts match exactly.
  • src/compat/hybrid_array_0_4.rs:64 (unsafe { core::mem::transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Exclusive mutable reference cast between identical transparent layouts.
  • src/compat/hybrid_array_0_4.rs:70 (unsafe { crate::const_transmute(self) }): Missing // SAFETY: comment.
    • Proposed Proof: Value cast between identical layouts.
  • src/compat/hybrid_array_0_4.rs:76 (unsafe { crate::const_transmute(value) }): Missing // SAFETY: comment.
    • Proposed Proof: Reverse value cast.

Module src/impl_alloc.rs (4 locations) 🔴

  • src/impl_alloc.rs:13 (unsafe { ... } in TryFrom<Vec>): Missing // SAFETY: comment.
    • Proposed Proof: Length verified equal to N::USIZE; IntrusiveArrayBuilder tracks element transfer from vector iterator.
  • src/impl_alloc.rs:56 (unsafe { Box::from_raw(...) }): Missing // SAFETY: comment.
    • Proposed Proof: Box<[T]> of length N and Box<GenericArray<T, N>> possess identical allocator layout.
  • src/impl_alloc.rs:158 (unsafe impl GenericSequence for Box<GenericArray<T, N>>): Missing // SAFETY: comment.
    • Proposed Proof: Boxed array sequence delegation preserves length invariants.
  • src/impl_alloc.rs:166 (unsafe { ... } in generate): Missing // SAFETY: comment.
    • Proposed Proof: Note: Assumes alloc returns non-null (see Critical Findings). IntrusiveArrayBuilder tracks partial init.

Module src/impl_serde.rs (1 location) 🔴

  • src/impl_serde.rs:65 (unsafe { ... } in GAVisitor::visit_seq): Missing // SAFETY: comment.
    • Proposed Proof: IntrusiveArrayBuilder ensures partially unpacked sequence elements drop cleanly if deserializer returns early error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions