Skip to content

Challenge 25: Verify Vecdeque safety with Kani#605

Draft
v3risec wants to merge 4 commits into
model-checking:mainfrom
v3risec:challenge-25-vecdeque
Draft

Challenge 25: Verify Vecdeque safety with Kani#605
v3risec wants to merge 4 commits into
model-checking:mainfrom
v3risec:challenge-25-vecdeque

Conversation

@v3risec

@v3risec v3risec commented Jun 29, 2026

Copy link
Copy Markdown

Summary

This PR adds Kani-based verification proofs for VecDeque functions in library/alloc/src/collections/vec_deque/mod.rs for Challenge 25: Verify the safety of VecDeque functions.

The change introduces:

  • safety contracts for the Challenge 25 unsafe VecDeque helpers
  • proof harness modules under #[cfg(kani)] for all Challenge 25 listed entries
  • reusable symbolic VecDeque helpers for initialized, bounded, unbounded, ZST, and reserve-sensitive states
  • Kani loop contracts and Kani-only loop structure for iterator-writing and retain paths

Verification Coverage Report

Coverage: 43 / 43 Challenge 25 entries targeted

Unsafe helper coverage includes:

  • push_unchecked
  • buffer_read
  • buffer_write
  • buffer_range
  • copy
  • copy_nonoverlapping
  • wrap_copy
  • copy_slice
  • write_iter
  • write_iter_wrapping
  • handle_capacity_increase
  • from_contiguous_raw_parts_in
  • abort_shrink

Safe abstraction coverage includes:

  • get
  • get_mut
  • swap
  • reserve_exact
  • reserve
  • try_reserve_exact
  • try_reserve
  • shrink_to
  • truncate
  • as_slices
  • as_mut_slices
  • range
  • range_mut
  • drain
  • pop_front
  • pop_back
  • push_front
  • push_back
  • insert
  • remove
  • split_off
  • append
  • retain_mut
  • grow
  • resize_with
  • make_contiguous
  • rotate_left
  • rotate_right
  • rotate_left_inner
  • rotate_right_inner

Approach

The verification strategy combines executable harnesses with targeted contracts, loop annotations, and path-specific symbolic states:

  1. Add precondition and modifies contracts for unsafe VecDeque helper functions that read, write, copy, or rearrange the ring buffer.
  2. Add #[kani::proof] and #[kani::proof_for_contract] harnesses for each Challenge 25 target, using concrete instantiations across integer types, usize/isize, unit/ZSTs, and arrays.
  3. Use initialized-buffer symbolic VecDeque builders where harnesses need to vary head and len independently without pointing logical elements at uninitialized storage.
  4. Split branch-heavy internal routines into dedicated harness families: handle_capacity_increase is covered through its non-wrapped, wrapped-tail, and remaining wrapped cases; abort_shrink is similarly covered through its different internal paths.
  5. Add Kani loop invariants and modifies sets for loops that write through raw buffer pointers or repeatedly move/retain elements.

Bounded and Unbounded Modeling Notes

The proofs do not rely on loop unwinding for the annotated loops; loop contracts
are used where needed.

The harnesses use both unbounded and bounded symbolic states:

  • Some harnesses leave logical lengths and capacities without small explicit bounds, so they exercise unbounded-style states subject only to validity, allocation-layout, and contract preconditions. In these cases, capacities can be very large, approaching the Rust allocation limits such as isize::MAX bytes where the standard library permits it.

  • Some harnesses intentionally bound allocation sizes because Kani/CBMC heap write-set reasoning has practical CAR limitations. In particular, heap write-set objects near the upper allocation range can exceed CBMC's capacity for precise write-set tracking; the practical threshold appears around the 2^51 to 2^47 range depending on the proof shape and element type.

  • A few harnesses use a small bound such as MAX_VEC_DEQUE_LEN = 4. These are targeted proofs for branch-heavy operations where the goal is to cover ring-buffer layouts, wrapping/non-wrapping states, growth/shrink paths, and ZST behavior without making heap write-set reasoning dominate the proof.

These bounds are verification engineering constraints rather than semantic preconditions on VecDeque; the production implementation remains unchanged, and bounded helpers are kept under cfg(kani).

Scope Assumptions

  • Generic T is represented through a broad set of concrete instantiations used by the harness macros.
  • ZST states are modeled separately because VecDeque::<()>::capacity() is logically usize::MAX and does not require backing storage.
  • Reserve-sensitive harnesses assume away capacity-overflow paths when the target proof is normal execution after successful reservation.

Verification

All added Challenge 25 harnesses pass locally with Kani.

Resolves #286

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Challenge 25: Verify the safety of VecDeque functions

1 participant