Fail verification when the solver backend drops quantifiers - #4719
Fail verification when the solver backend drops quantifiers#4719tautschnig wants to merge 5 commits into
Conversation
CBMC's SAT-based backends only support quantifiers with constant bounds. A quantifier with a symbolic bound reaches the backend's quantifier post-processing, which has no handling and replaces the expression with unconstrained values, reporting only a low-visibility 'warning: ignoring forall' among CBMC's status messages (which Kani does not surface). The consequences are severe for usability: a kani::assume containing such a quantifier is silently NOT enforced -- the harness may verify successfully while covering none of the intended property -- and a kani::assert containing one may fail spuriously. Detect CBMC's ignoring-quantifier messages in the output parser, count them on VerificationResult, and render a prominent warning after the result (on both successful and failed outcomes) explaining the effect and suggesting an SMT solver backend (#[kani::solver(z3)]), which supports these quantifiers. The new expected test pins the dangerous case: a harness that SUCCEEDS only because its final assertion does not depend on the (unenforced) quantified assumption, with the warning attached. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves Kani’s user-facing diagnostics around CBMC SAT-backend quantifiers by detecting CBMC “ignoring forall/exists” messages, tracking how many quantifier expressions were dropped, and emitting a prominent warning so users don’t mistake vacuous assumes (or spurious assert failures) for reliable results.
Changes:
- Add parsing/counting of CBMC “ignoring forall/exists” messages and plumb the count into
VerificationResult. - Render a prominent, multi-line warning when dropped quantifiers are detected.
- Add a new expected test that pins the dangerous “vacuous assume” scenario and asserts the warning is emitted.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/expected/quantifiers/ignored_quantifier_warning.rs | New regression test harness that triggers a symbolic-bound quantifier being dropped. |
| tests/expected/quantifiers/ignored_quantifier_warning.expected | Expected output asserting the new prominent warning is printed. |
| kani-driver/src/call_cbmc.rs | Counts ignored-quantifier messages and renders a warning via VerificationResult. |
| Cargo.lock | Updates locked charon version (appears unrelated to the PR’s stated scope). |
Suppressed comments (1)
kani-driver/src/call_cbmc.rs:461
- The ignored-quantifier warning is appended after
format_result/format_coverage, which already ends with the finalVERIFICATION:- ...line. This means the warning currently prints after the overall status line (and with an extra blank line), but the new expected test output places the warning beforeVERIFICATION:- ...so it’s not missed on successful runs.
if self.ignored_quantifiers > 0 {
result.push('\n');
result.push_str(&ignored_quantifiers_warning(self.ignored_quantifiers));
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… verdict Three fixes to the ignored-quantifier warning change: - Add the new `ignored_quantifiers` field to the two `VerificationResult` literals in `sarif.rs`'s test module. Without them `cargo test`/ `cargo clippy --tests` fail to compile (`missing field ignored_quantifiers`), which is what broke the clippy-check and the kani-driver unit tests in the regression job. - Rename the regression test from `ignored_quantifier_warning` to `dropped_quantifier_warning`. compiletest skips any test whose path contains "ignore" (see `tools/compiletest/src/header.rs`), so the test was silently ignored and never actually ran. - Render the warning immediately before the `VERIFICATION:- ...` line rather than after it, so a reliability warning is not missed when the run otherwise reports success (this also matches the order in the `.expected` file). Falls back to appending when there is no such line (e.g. coverage output). Signed-off-by: Felipe Monteiro <felisous@amazon.com>
Commit 65c183c ("Warn prominently when the solver backend drops quantifiers") inadvertently swept in a stale charon submodule pointer (607f5683 -> dee66030, a downgrade from 0.1.88 to 0.1.73) and the matching Cargo.lock change. These are unrelated to the quantifier warning feature. Restore charon to 607f5683 / 0.1.88.
…ntifiers-fixes # Conflicts: # kani-driver/src/call_cbmc.rs
When CBMC's SAT backend cannot encode a quantifier with non-constant bounds, it drops it and replaces it with an unconstrained value. A `kani::assume` containing such a quantifier is then silently not enforced, so a "SUCCESSFUL" verdict can be vacuous -- an unsound false negative, which Kani must never produce. Instead of only printing a warning, force the verification to FAIL (VerificationStatus::Failure / FailedProperties::Error) when any quantifier was dropped, and render an error directing users to an SMT solver backend that supports quantifiers, e.g. `#[kani::solver(z3)]`. Also: - Fix a merge-integration bug: schema_utils_test.rs constructed VerificationResult without the `ignored_quantifiers` field, breaking the test build. - Rename the dropped_quantifier_warning expected test to dropped_quantifier_error and update it to assert VERIFICATION:- FAILED. - Document the solver-backend limitation in the quantifiers reference.
|
Behavior change (experimental @tautschnig do you agree to merge it with this new behavior? |
Description
CBMC's SAT-based backends only support quantifiers with constant bounds (
boolbv_quantifier.cpp's eager instantiation). Akani::forall!/kani::exists!with a symbolic bound reaches the backend's quantifier post-processing, which has no handling: the expression is replaced with unconstrained values, and CBMC reports only a low-visibilitywarning: ignoring forallamong its status messages — which Kani currently swallows entirely.The consequences are severe for usability:
kani::assumecontaining such a quantifier is silently not enforced: the harness may reportVERIFICATION:- SUCCESSFULwhile covering none of the intended property (found while building quantified element-validity assumptions for autoharness slice generation, where the vacuous assume was only caught by a non-tautological probe);kani::assertcontaining one may fail spuriously.This PR detects CBMC's ignoring-quantifier messages in the output parser, counts them on
VerificationResult, and renders a prominent warning after the result (on both successful and failed outcomes), explaining the effect and suggesting#[kani::solver(z3)], which handles these quantifiers (verified: the same harnesses verify correctly, fast, under z3).A proper fix (quantifier instantiation in CBMC's SAT backend) is in progress upstream; this warning closes the silent-degradation window until it lands.
Testing
New expected test pins the dangerous case: a harness that succeeds only because its assertion does not depend on the (unenforced) quantified assumption, with the warning attached. Verified no-warning behavior for constant-bound quantifiers (eagerly instantiated) and under
--solver z3. All quantifier expected tests and kani-driver unit tests pass.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.