Respect new_unchecked precondition in IndexRange proof harnesses - #623
Open
tautschnig wants to merge 1 commit into
Open
Respect new_unchecked precondition in IndexRange proof harnesses#623tautschnig wants to merge 1 commit into
tautschnig wants to merge 1 commit into
Conversation
The proof_for_contract harnesses for IndexRange::next_unchecked and IndexRange::next_back_unchecked, introduced in commit a0fca1c ("A bunch of LLM-generated contracts (model-checking#451)"), construct their IndexRange via `IndexRange::new_unchecked(start, end)` with entirely unconstrained `start` and `end`. That violates new_unchecked's documented safety precondition (and #[requires] contract) `start <= end`: the assumption provided by the contract under verification only takes effect at the call to next_unchecked / next_back_unchecked, after the UB of the unchecked constructor call has already happened. The violation is currently invisible in CI because run-kani.sh passes --no-assert-contracts; with dependency contracts asserted (the Kani default since model-checking/kani#3802), proof_for_index_range_next_back_unchecked fails on the asserted `start <= end` clause. Constrain both harnesses with `kani::assume(start <= end)`. The stronger `start < end` required by the functions under verification continues to be assumed from their own contracts, preserving the intent of the harnesses. Verified (Kani 152c6a8c + CBMC 6.10.0) that all three ops::index_range::verify harnesses pass both with and without --no-assert-contracts. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes Kani contract-proof harnesses for IndexRange::next_unchecked and IndexRange::next_back_unchecked so they do not invoke IndexRange::new_unchecked with inputs that violate its documented safety precondition (start <= end). This prevents a latent UB/contract violation from being masked when dependency contracts are asserted (the Kani default).
Changes:
- Add
kani::assume(start <= end)in theproof_for_contractharness forIndexRange::next_unchecked. - Add
kani::assume(start <= end)in theproof_for_contractharness forIndexRange::next_back_unchecked. - Document why this assumption is needed (constructor precondition) and why the stricter
start < endcondition is still covered by the verified functions’ own contracts.
feliperodri
reviewed
Aug 3, 2026
Comment on lines
+253
to
+256
| // Respect new_unchecked's safety precondition (start <= end); the | ||
| // stronger requirement of next_unchecked (start < end) is assumed | ||
| // from its contract. | ||
| kani::assume(start <= end); |
Member
There was a problem hiding this comment.
shouldn't this be part of the requires clause for new_unchecked?
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.
The
proof_for_contractharnesses forIndexRange::next_uncheckedandIndexRange::next_back_unchecked, introduced in a0fca1c (#451), construct theirIndexRangeviaIndexRange::new_unchecked(start, end)with entirely unconstrainedstartandend. That violatesnew_unchecked's documented safety precondition (and#[requires]contract)start <= end: the assumption provided by the contract under verification only takes effect at the call tonext_unchecked/next_back_unchecked, after the UB of the unchecked constructor call has already happened.The violation is currently invisible in CI because
run-kani.shpasses--no-assert-contracts; with dependency contracts asserted (the Kani default since model-checking/kani#3802),proof_for_index_range_next_back_uncheckedfails on the assertedstart <= endclause.This PR constrains both harnesses with
kani::assume(start <= end). The strongerstart < endrequired by the functions under verification continues to be assumed from their own contracts, preserving the intent of the harnesses.Verified with Kani 152c6a8c + CBMC 6.10.0: all three
ops::index_range::verifyharnesses pass both with and without--no-assert-contracts.Found while investigating what still blocks removing
--no-assert-contractsfromrun-kani.sh: this is one of two genuine latent contract violations that asserting dependency contracts surfaces (the other: #622).By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.