Autoharness: unbounded slice, mutable slice and Vec arguments - #4721
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Extends Kani’s autoharness value generation to cover more real-world argument shapes by adding (1) unbounded models for slice references/mutable slices and Vec<T> (for qualifying element types) and (2) constructor-based generation for private-field structs to avoid invariant-violating raw field synthesis, plus supporting metadata/reporting and regression tests.
Changes:
- Add optional
alloc-backed unbounded models for&[T],&mut [T], andVec<T>plus a hook for element validity assumptions. - Add
--constructor-argsplumbing and metadata (is_ctor_based) to mark under-approximating constructor-based harnesses. - Add new script-based regression tests and docs updates for the new autoharness behaviors.
Reviewed changes
Copilot reviewed 30 out of 31 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/script-based-pre/cargo_autoharness_vec_unbounded/vec.sh | Runs new unbounded-Vec autoharness regression. |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/vec.expected | Pins expected autoharness output including unwinding failure. |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/src/lib.rs | Test crate covering unbounded Vec<T> + mutable slice behavior. |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/config.yml | Script-based test configuration (expects failure). |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/Cargo.toml | New test crate manifest. |
| tests/script-based-pre/cargo_autoharness_constructor/src/lib.rs | Test crate for ctor-based generation and assert-mined filtering. |
| tests/script-based-pre/cargo_autoharness_constructor/constructor.sh | Runs autoharness with/without --constructor-args and normalizes output. |
| tests/script-based-pre/cargo_autoharness_constructor/constructor.expected | Expected output demonstrating ctor-marked harnesses. |
| tests/script-based-pre/cargo_autoharness_constructor/config.yml | Script-based test configuration. |
| tests/script-based-pre/cargo_autoharness_constructor/Cargo.toml | New test crate manifest. |
| tests/script-based-pre/autoharness_niche/run.sh | Runs niche validity regression via autoharness. |
| tests/script-based-pre/autoharness_niche/niche_probe.rs | Defines a niche-ranged scalar type used to validate niche assumptions. |
| tests/script-based-pre/autoharness_niche/expected | Expected success output for niche regression. |
| tests/script-based-pre/autoharness_niche/config.yml | Script-based test configuration. |
| library/kani/src/arbitrary.rs | Adds unbounded slice/vec models and the slice_validity_assume hook stub. |
| kani-driver/src/sarif.rs | Updates SARIF test scaffolding for new harness metadata field. |
| kani-driver/src/metadata.rs | Updates metadata test scaffolding for new harness metadata field. |
| kani-driver/src/autoharness/mod.rs | Adds ctor-harness marker rendering and passes ctor flag into compiler args. |
| kani-driver/src/args/autoharness_args.rs | Adds --constructor-args (and documents --bounded-arguments). |
| kani-compiler/src/kani_middle/transform/body.rs | Adds basic-block helpers used for inlining. |
| kani-compiler/src/kani_middle/transform/automatic.rs | Adds constructor-based generation, inlining with mined assertions, scalar niche assumptions, and unbounded model routing. |
| kani-compiler/src/kani_middle/mod.rs | Adds ctor selection logic, scalar niche extraction, and slice/vec element qualification logic. |
| kani-compiler/src/kani_middle/metadata.rs | Adds is_ctor_based plumbing to autoharness metadata generation. |
| kani-compiler/src/kani_middle/kani_functions.rs | Adds new models/hooks and marks alloc-backed models as optional. |
| kani-compiler/src/kani_middle/codegen_units.rs | Threads ctor-based marking into harness selection; admits unbounded slice/vec args when models exist. |
| kani-compiler/src/codegen_cprover_gotoc/overrides/hooks.rs | Lowers slice_validity_assume into a quantified assumption in goto. |
| kani-compiler/src/args.rs | Adds compiler-side flags for bounded-args and ctor-args autoharness options. |
| kani_metadata/src/harness.rs | Adds persisted is_ctor_based field to harness metadata. |
| docs/src/reference/experimental/autoharness.md | Documents --constructor-args behavior and its under-approximation. |
| Cargo.lock | Updates the locked charon version entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
feliperodri
force-pushed
the
unbounded-pr
branch
from
August 25, 2026 20:56
08a000c to
a3a8f9b
Compare
feliperodri
approved these changes
Aug 25, 2026
feliperodri
enabled auto-merge
August 25, 2026 21:00
Arguments of type &[T], &mut [T] and Vec<T> whose element type is a primitive integer or float are now supported, generated UNBOUNDED: the new optional (alloc-requiring) models allocate nondeterministic-size storage, so verification results hold for ALL lengths. Functions that iterate over the data surface insufficient loop bounds as visible unwinding-assertion failures rather than silently bounded successes. Mutable slices are exclusive by construction (each call leaks a fresh allocation); Vec uses from_raw_parts with capacity matching the allocation layout and frees on drop (ZST elements use the documented dangling-pointer pattern, loop-free). Element types are restricted to those where raw nondeterministic memory needs NO validity assumption (every bit pattern valid): the companion SliceValidityAssume hook, lowered directly to pure quantified goto expressions, exists for niched element types (bool, NonZero*), but CBMC's SAT backend only instantiates constant-bound quantifiers and silently drops symbolic-bound ones (see model-checking#4719), so those element types remain unsupported until the in-progress CBMC quantifier work lands. Rebased onto the mining-constructor PR (model-checking#4718): folds `unbounded_models` into the `AnyModels` bundle and registers `cfg(kani)` for the library build. Also folds in review-driven hardening: require all three unbounded models present before admitting slice/Vec args in partitioning (so eligibility cannot diverge from generation), verify the resolved model's return type matches the argument type in `instance_for`, and match the `Global` allocator exactly rather than by substring in `vec_elem_ty`. Update existing autoharness .expected tests (slices, bounded, filter) for the new unbounded behavior: `&[T]`/`&mut [T]`/`Vec<T>` of primitive integer/float elements are now generated unbounded (no "(bounded)" marker) and are eligible without --bounded-arguments. In particular vec_sum now overflows u64 with an unbounded Vec (Failure), and filter's no_harness slice/Vec functions are now selected (47 -> 50). Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
feliperodri
force-pushed
the
unbounded-pr
branch
from
August 25, 2026 21:59
a3a8f9b to
7018ed7
Compare
Merged
via the queue into
model-checking:main
with commit Aug 25, 2026
5da96e5
33 of 34 checks passed
feliperodri
pushed a commit
to tautschnig/kani
that referenced
this pull request
Aug 26, 2026
Corpus grounding: 1,977 methods across 131 of the top-500 crates assert conditions over their own receiver's fields — a rich, directly-usable invariant source. The new kani_middle::mined_invariants module extracts such assertions into a pure expression AST. Admission requires: the assert executes on every normal return (post-dominance; for enums, post-dominance of a match arm on self's discriminant, yielding variant-guarded conjuncts), the condition's backward slice is call-free and single-assignment (one-level pure-getter inlining excepted; match-ergonomics reference bindings cancelled), and the conjunct is asserted in at least two distinct methods (rejecting method-local preconditions). The AST doubles as the canonical form for that cross-method filter and re-materializes as total, loop-free MIR (variant-guarded conjuncts emit implications over the discriminant). Consumers: - under --constructor-args (same heuristic-filter umbrella and '(ctor)' marker): generated ADT values assume the mined conjuncts — covering types with no viable constructor, at lower formula cost than constructor inlining; - NEW --check-invariants: values returned by verified functions are CHECKED against the mined conjuncts — through &T and the payloads of Option<T>/Result<T, E> (None/Err pass vacuously via a discriminant guard) — with a distinct property message naming the asserting methods: automatic invariant-preservation checking. The regression test pins eight behaviors incl. struct/enum invariants assumed, getter-mined conditions, buggy direct and Result producers caught, and single-method preconditions honestly not mined. Rebased onto the unbounded-args PR (model-checking#4721): folds `constructor_args` into the `AnyModels` bundle and threads a `mined_cache` for memoization. Also folds in review-driven hardening and toolchain-drift fixes: make `build_guarded_conjunct` bail (skip) rather than emit an unguarded enum conjunct, skip the `--check-invariants` payload check when its wrapper discriminant guard cannot be built, and treat unmodeled terminators (e.g. InlineAsm with a normal successor) conservatively in `postdominates`. The docs now cover `--check-invariants` and the generalized `(ctor)` marker, and note the heuristic-assume caveat (tracked in model-checking#4763). Clippy/doc lint fixes for the new module round it out. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
feliperodri
pushed a commit
to tautschnig/kani
that referenced
this pull request
Aug 26, 2026
…-checking#4722) ### Description Stacked on model-checking#4716/model-checking#4717/model-checking#4718/model-checking#4721 (review only the last commit). Mines type invariants from a type's *own assertions*: conditions over the receiver's fields asserted on every normal return path of **at least two** distinct methods (a frequency filter against method-local preconditions). Corpus grounding: 1,977 such assertion sites across 131 of the top-500 crates. Admission is conservative — post-dominance (per match-arm for enums, yielding variant-guarded conjuncts), call-free single-assignment backward slices (one-level pure-getter inlining excepted), extraction into a pure expression AST that re-materializes as total, loop-free MIR. Two consumers: - under `--constructor-args` (same heuristic umbrella, same "(ctor)" marker): generated values **assume** the mined conjuncts — covering types with no viable constructor, at lower formula cost than constructor inlining; - new `--check-invariants`: values returned by verified functions are **checked** against the mined conjuncts — through `&T` and `Option`/`Result` payloads (`None`/`Err` pass vacuously) — with a distinct property message naming the asserting methods. This turns autoharness into an automatic invariant-preservation checker: the classic "constructors establish, methods preserve" obligation, with zero annotations. ### Testing The regression test pins eight behaviors: struct and enum (variant-guarded) invariants assumed for generated values (false alarms eliminated, markers attached); getter-mined conditions; a buggy producer returning an invariant-violating value caught by the output check (direct and `Result`-wrapped); correct producers and `Err` paths passing; and a single-method precondition honestly *not* mined. Constructor/niche/vec/autoderive suites pass. Towards model-checking#3832. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
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.
Description
Stacked on #4716/#4717/#4718 (review only the last commit).
Adds autoharness support for
&[T],&mut [T]andVec<T>arguments with primitive integer/float element types, generated unbounded: fresh allocations of nondeterministic size, so verification results hold for all lengths. Loops that cannot be fully unwound surface as visible unwinding-assertion failures instead of silently bounded successes — the soundness-signaling design validated in the top-500 evaluations (#3832).&mut [T]: each call leaks a fresh allocation, so the slice is exclusive by construction.Vec<T>:from_raw_partswith capacity matching the allocation layout (freed on drop); ZST elements use the documented dangling-pointer pattern (loop-free, as generation code must be).alloc), following the smart-pointer-model precedent: absent inverify-std's no-core flow, where these argument types simply stay unsupported.SliceValidityAssumehook (lowered directly to pure quantified goto expressions, bypassing the closure-based quantifier path) exists for niched element types, but CBMC's SAT backend silently drops symbolic-bound quantifiers (Fail verification when the solver backend drops quantifiers #4719), sobool/NonZero*elements remain unsupported until the in-progress CBMC quantifier-instantiation work lands — at which pointslice_elem_unbounded_okre-admits them.Corpus measurement (top-500, full-stack sweep): zero ICEs; the expected shift of silently-bounded loop successes into visible unwinding failures (http 6→18, prost 0→14, encoding_rs 26→35) with loop-free properties over slices/Vecs verifying for all lengths (covers pin lengths beyond 100,000).
Testing
New
cargo_autoharness_vec_unboundedtest: loop-free accessors pass for all lengths, covers verify large lengths/extreme contents/empty values reachable, a looping consumer pins the visible unwinding-failure contract, and a mutable-slice writer verifies. Constructor/niche/autoderive suites pass.Towards #3832.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.