Learn · All the Ways It Can Break
growing
A Contract Can Replace an Implementation
Verify a function body once, then reason about callers through the behavior its contract exposes.
You will verify the midpoint function's precondition and postcondition, explain verified stubbing, generate a concrete playback test from the broken harness, and transfer the workflow to a different function without confusing a replay with a proof.
State the seam
The repaired midpoint carries this contract:
#[kani::requires(low <= high)]
#[kani::ensures(|result: &u8| low <= *result && *result <= high)]
fn midpoint(low: u8, high: u8) -> u8 {
low + (high - low) / 2
}The precondition is not checked on arbitrary production calls merely because it is written here. In verification, callers must establish it. The postcondition intentionally promises interval containment, not the exact rounding rule; a client that depends on lower-midpoint rounding needs a stronger contract.
Kani 0.67.0 marks function contracts experimental, so enable the feature explicitly:
rust code/all-the-ways-it-can-break/numeric-kani/numeric.rs#contract numeric.rs proof_for_contract supplies symbolic arguments and checks the real body against requires and ensures.
cargo kani -Z function-contracts --harness midpoint_contractA verified stub replaces a function body during one proof with nondeterministic behavior constrained by its contract. Kani documents the workflow in its function-contracts guide.
Compose only after verification
A caller harness may add #[kani::stub_verified(midpoint)]. Kani then avoids re-exploring the implementation and assumes only results allowed by ensures, provided the caller satisfies requires. Preserve two separately checked artifacts:
- the contract proof over the exact function body and toolchain identity;
- the caller proof that uses that exact verified contract.
Changing the body, feature set, or contract invalidates the composition until the contract proof runs again. A build graph should encode that dependency rather than relying on a note in a review.
Turn one counterexample into a regression test
Run the broken harness with concrete playback output:
cargo kani --harness buggy_midpoint_stays_in_range --concrete-playback printKani prints a Rust unit test containing concrete symbolic choices from the failure. Keep a minimized version beside ordinary tests when it explains the bug. The unit test makes the witness cheap to replay on future builds; it does not replace the symbolic proof, because it covers one assignment only. Regenerate or repair playback when harness control flow changes and consumes symbolic values differently.
Unlike transfer: bounded slicing
Write a function that returns a slice between start and end. Its contract requires start < end <= input.len()= and ensures the result length is end - start. First prove the implementation contract. Then verify a caller's copy loop using a verified stub. Deliberately weaken the postcondition to result.len() < input.len()= and observe which caller proof can no longer be established.
Lessons
requiresis a caller obligation;ensuresis a callee promise.proof_for_contractchecks the real body before composition.stub_verifiedreplaces implementation detail with contract-constrained behavior.- A true but weak contract may be unusable.
- Concrete playback preserves one witness; symbolic verification covers the admitted domain.
- Experimental feature flags and exact tool versions belong in the evidence record.
Practice
- Retrieval. Which side must establish a precondition?
- Discrimination. May a generated playback test replace the repaired symbolic harness?
- Transfer. Complete the bounded-slice contract and caller proof, then weaken the postcondition deliberately.
Worked answers
- Every verified caller must establish
requiresbefore invoking or stubbing the callee. - No. Playback retains one counterexample; the harness asks about every admitted symbolic value.
- The useful postcondition relates output length to
end - start. The weaker global length bound cannot justify a caller that copies exactly the selected range.
References
- Kani. Function contracts. — preconditions, postconditions, contract proof, and verified stubbing
- Kani. Concrete playback. — generating executable tests from counterexamples