Autoharness: mine type invariants from a type's own assertions - #4722
Open
tautschnig wants to merge 1 commit into
Open
Autoharness: mine type invariants from a type's own assertions#4722tautschnig wants to merge 1 commit into
tautschnig wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Extends Kani’s autoharness pipeline to reduce false alarms from invalid autogenerated inputs by (1) generating/ filtering values using constructor- and assertion-derived heuristics, and (2) adding optional invariant checking on function return values; it also introduces unbounded generation models for qualifying slice/Vec arguments to make results hold for all lengths.
Changes:
- Add mining of type invariants from a type’s own
assert-style conditions and use them as (a) generation filters and (b) return-value checks (--check-invariants). - Add unbounded argument generation models for
&[T],&mut [T], andVec<T>when element types qualify, plus a compiler hook for element validity assumptions. - Plumb new autoharness CLI/compiler flags and metadata (
is_ctor_based) through reporting (including the “(ctor)” marker).
Reviewed changes
Copilot reviewed 36 out of 37 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 | Scripted regression driver for unbounded Vec/slice argument generation. |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/vec.expected | Expected output for the unbounded Vec/slice regression. |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/src/lib.rs | Test crate exercising unbounded Vec/slice behaviors (coverage + unwinding failures). |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/config.yml | Script-based test config (expects non-zero exit due to unwinding failure). |
| tests/script-based-pre/cargo_autoharness_vec_unbounded/Cargo.toml | Test crate manifest for the unbounded Vec/slice regression. |
| tests/script-based-pre/cargo_autoharness_mined_invariants/src/lib.rs | Test crate covering invariant mining frequency filter, getter mining, enum variant guards, and return checking. |
| tests/script-based-pre/cargo_autoharness_mined_invariants/mined.sh | Scripted regression driver enabling --constructor-args and --check-invariants. |
| tests/script-based-pre/cargo_autoharness_mined_invariants/mined.expected | Expected output including the distinct “mined invariant … violated” property. |
| tests/script-based-pre/cargo_autoharness_mined_invariants/config.yml | Script-based test config for mined invariants. |
| tests/script-based-pre/cargo_autoharness_mined_invariants/Cargo.toml | Test crate manifest for mined invariants regression. |
| tests/script-based-pre/cargo_autoharness_constructor/src/lib.rs | Test crate for constructor-based generation and nested unchecked constructor inlining. |
| tests/script-based-pre/cargo_autoharness_constructor/constructor.sh | Script comparing outputs with/without --constructor-args. |
| tests/script-based-pre/cargo_autoharness_constructor/constructor.expected | Expected output for constructor-based generation, including “(ctor)” markers. |
| tests/script-based-pre/cargo_autoharness_constructor/config.yml | Script-based test config for constructor generation. |
| tests/script-based-pre/cargo_autoharness_constructor/Cargo.toml | Test crate manifest for constructor generation regression. |
| tests/script-based-pre/autoharness_niche/run.sh | Scripted regression driver for scalar niche validity assumptions. |
| tests/script-based-pre/autoharness_niche/niche_probe.rs | Test crate probing rustc_layout_scalar_valid_range niches. |
| tests/script-based-pre/autoharness_niche/expected | Expected output for niche validity regression. |
| tests/script-based-pre/autoharness_niche/config.yml | Script-based test config for niche regression. |
| library/kani/src/arbitrary.rs | Adds unbounded slice/Vec generation models plus the slice_validity_assume compiler hook marker. |
| kani-driver/src/sarif.rs | Updates test scaffolding to include new is_ctor_based metadata field. |
| kani-driver/src/metadata.rs | Updates test scaffolding to include new is_ctor_based metadata field. |
| kani-driver/src/autoharness/mod.rs | Forwards new autoharness flags into compiler args and renders “(ctor)” marker in summary output. |
| kani-driver/src/args/autoharness_args.rs | Adds CLI flags for constructor-based generation and mined-invariant checking (and bounded arguments). |
| kani-compiler/src/kani_middle/transform/body.rs | Adds MIR body utilities used by constructor inlining. |
| kani-compiler/src/kani_middle/transform/automatic.rs | Implements constructor-arg generation, unchecked-constructor inlining with assumed panics, mined invariant assume/check, and unbounded models integration. |
| kani-compiler/src/kani_middle/mod.rs | Adds constructor discovery, ctor-based marker detection, unbounded element qualification, and scalar niche extraction utilities. |
| kani-compiler/src/kani_middle/mined_invariants.rs | New module implementing invariant mining from a type’s own assertions. |
| kani-compiler/src/kani_middle/metadata.rs | Threads is_ctor_based into automatic harness metadata generation. |
| kani-compiler/src/kani_middle/kani_functions.rs | Adds optional unbounded models and the SliceValidityAssume hook marker; relaxes validation for optional models. |
| kani-compiler/src/kani_middle/codegen_units.rs | Extends harness selection pipeline to compute/store ctor-based marker and admit unbounded slice/Vec arguments when models are present. |
| kani-compiler/src/codegen_cprover_gotoc/overrides/hooks.rs | Lowers slice_validity_assume hook to a quantified CBMC assumption. |
| kani-compiler/src/args.rs | Adds compiler-side autoharness flags for bounded args, constructor args, and invariant checking. |
| kani_metadata/src/harness.rs | Adds serialized is_ctor_based field to harness metadata. |
| docs/src/reference/experimental/autoharness.md | Documents --constructor-args (but not yet --check-invariants). |
| Cargo.lock | Updates dependency lockfile (includes a charon version change). |
Suppressed comments (2)
kani-compiler/src/kani_middle/mined_invariants.rs:356
- Duplicated text in this doc comment ("Whether
pis a temp holding&self" appears twice) looks unintentional.
/// Whether `p` is a temp holding `&self`/// Whether `p` is a temp holding `&self` (defined once as `Ref(.., self-place)`).
kani-driver/src/autoharness/mod.rs:171
add_auto_harness_argscurrently forwards include/exclude patterns plus--autoharness-constructor-args/--autoharness-check-invariants, but it never forwards--autoharness-bounded-arguments, sokani autoharness --bounded-argumentswon’t change compiler behavior.
&mut self,
included: &[String],
excluded: &[String],
constructor_args: bool,
check_invariants: bool,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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
approved these changes
Aug 26, 2026
feliperodri
enabled auto-merge
August 26, 2026 02:05
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/#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:
--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;--check-invariants: values returned by verified functions are checked against the mined conjuncts — through&TandOption/Resultpayloads (None/Errpass 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 andErrpaths passing; and a single-method precondition honestly not mined. Constructor/niche/vec/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.