Conversation
Add mod verify harnesses for all 22 Challenge 24 targets in IntoIter and the spec_extend / spec_from_iter / spec_from_elem / extract_if helpers. Harnesses exercise the real shipped bodies (no cfg(kani) rewrites) over symbolic-length inputs, with every kani::assume paired with a satisfied kani::cover. Unbounded and generic-T are not literally met (committee gate) and are disclosed. Additive only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TLDR: Kani harnesses for all 22 Challenge 24 targets (
Vec::IntoIter+ thespec_*/from_elem/extract_ifhelpers) — 26 harnesses verifying the real shipped bodies (nocfg(kani)rewrites) over symbolic-length inputs, with functional postconditions and ZST-arm coverage. Unbounded and generic-Tare not literally met — the same committee question open across the sentence-pair challenges — and are disclosed below.Towards #285.
Context
Challenge 24 covers the safety of
Vec's consuming iteratorIntoIter(library/alloc/src/vec/into_iter.rs) plus the specialization helpers it routes through (spec_extend,spec_from_iter,spec_from_iter_nested,spec_from_elem,extract_if). These read and advance a raw pointer pair (ptr/end) into a heap allocation, so the safety obligations are pointer in-bounds, no double-drop on early exit or panic, and correct handling of the ZST encoding (whereendwalks by bytes andptrstays fixed).Solution
26 harnesses across the 22 listed functions. Each exercises the function's actual shipped body — no
#[cfg(kani)]body substitution and nokani::assume(false)on any real branch — and asserts the function's observable effect, not just the absence of UB.kani::slice::any_slice_of_array+to_vec, so the pointer-walking loops (fold,try_fold,next/next_back,advance_by/advance_back_by) run a symbolic number of iterations up to the backing size (64 for theIntoIterharnesses; the allocation-heavy harnesses use smaller bounds, detailed under limitations).size_hint == (len, Some(len));next/next_backreturn exactly the first/last element and shrink the remaining length by one;advance_by(k)/advance_back_by(k)returnOkiffk <= len, with the remaining length checked in both branches;next_chunk::<2>succeeds ifflen >= 2;foldvisits exactlylenelements;from_elem(elem, n)produces lengthnwithv[j] == elemat a symbolic index;spec_extend/from_iterpreserve length and element values at a symbolic index;into_vecdequepreserves length.try_folduses a comparator that can short-circuit (Err), in both au8variant and aDrop-carrying variant whose remaining elements are destroyed byIntoIter's realDrop— the double-drop class the body'sptr.add(1)-before-fordering exists to prevent.dropandforget_allocation_drop_remainingalso use theDrop-carrying type.extract_if::nextreads and writes through the actualvec.as_mut_ptr().add(i)pointer (nocan_writeassumption).IntoItermethod has a structurally separateT::IS_ZSTbranch (byte-walkingend, fixedptr);next/fold/advance_byare verified onVec<()>at symbolic length, covering that distinct branch.__iterator_get_uncheckedalready carries#[requires(i < self.len())]+kani::modifies(self)onmain, previously with no exercising harness. Kani cannot resolve a generic trait-impl method as aproof_for_contracttarget (kani#1997), so the harness here is the mirroring assume-guarded proof, asserting the read's value against the source slice, with an in-code note.kani::coverwitness (12 covers total, including loop witnesses on the fold/drain harnesses).How to verify
Scoped to these harnesses (from the repo root):
Expected:
Complete - 26 successfully verified harnesses, 0 failures, 26 total.with1 of 1 cover properties satisfiedfor each of the 12 covers. The harnesses also run in the standard./scripts/run-kani.shsweep, as in CI. (Verified locally at Kani 0.67.0 / CBMC 6.10.0.)Reviewer notes — disclosed limitations
IntoIterfunctions; smaller where noted below). We also measured a loop-contract route to genuine unboundedness on theIntoIterpointer loops: once the loop contract havocs the pointer, the invariant must re-establish pointer validity viakani::mem::same_allocation, and CBMC does not terminate on that predicate for these loops. A minimalsame_allocationloop invariant over a stack array does verify, so the limit is specific to theIntoIterheap-pointer shape rather than the predicate in general; the index-based loop invariants used for thecoreiterators do not hit it. The bounded harnesses above are the working encoding today.T: not met. Harnesses use representative element types (u8,()for the ZST arm, and aDrop-carrying token for drop glue). This is the same acceptance question open across the sentence-pair challenges; deferring to the committee on whether representative-type coverage satisfies the clause.extract_if::next(3) and the defaultfrom_iter(4) exceed the CI-standard--object-bits 12object budget at larger sizes (measured); theDrop-token harnesses use a small fixed size (4) because drop obligations are per-element identical, so larger sizes add solver time without new proof obligations. Each bound is noted in-code at its site.spec_extendharnesses pre-size the destination soappend_elements'reserveis a no-op: the copy path is verified; element-by-element growth routes throughextend_desugared(a Challenge 23 target) whose reallocation branch exceeds the object-bits budget above.+496 / -0across 6 files); no runtime logic is modified.