Skip to content

Warn when quantifier range exceeds SAT solver threshold#4579

Merged
feliperodri merged 1 commit into
model-checking:mainfrom
feliperodri:warn-unbounded-quantifiers-sat
Apr 22, 2026
Merged

Warn when quantifier range exceeds SAT solver threshold#4579
feliperodri merged 1 commit into
model-checking:mainfrom
feliperodri:warn-unbounded-quantifiers-sat

Conversation

@feliperodri
Copy link
Copy Markdown
Contributor

@feliperodri feliperodri commented Apr 19, 2026

Emit a compile-time warning when an unbounded forall! or exists! quantifier is detected. SAT solvers (the default backend) expand quantifiers into one conjunction/disjunction per value in the range, so unbounded ranges (forall!(|i| ...) which expands over all 2^64 usize values) cause silent memory exhaustion or divergence with no diagnostic.

Contributes to #3273.

Problem

Writing forall!(|i| ...) (unbounded, ranging over all usize values) with the default SAT backend silently hangs or OOMs because CBMC expands the quantifier into 2^64 terms. Users get no feedback about why verification doesn't terminate.

Solution

  • warn_large_quantifier_range() in hooks.rs: At codegen time, checks if both quantifier bounds are compile-time integer constants. If the range exceeds QUANTIFIER_RANGE_WARN_THRESHOLD (1000), emits a span_warn suggesting tighter bounds or an SMT solver. For unbounded ranges (~2^64), uses a human-friendly message instead of the raw integer.
  • unwrap_to_constant(): Helper that unwraps typecasts and resolves symbol references via the symbol table to extract integer constants from bound expressions. Includes a depth limit (5) to guard against cycles.

Known limitation

Bounded quantifiers (forall!(|i in (0, 2000)| ...)) use let bindings in the macro expansion for type coercion, which hides the constant values from codegen. The warning currently only fires for unbounded quantifiers, which is the most dangerous case. Detecting large bounded ranges would require constant propagation through local variables, a potential follow-up improvement.

Example warning

warning: `kani::forall` has an unbounded (~2^64) range; SAT solvers (the default
         backend) expand quantifiers over every value and may exhaust memory or
         diverge. Consider adding tighter bounds or using an SMT solver
         (`#[kani::solver(z3)]` or `--solver z3`).
  --> tests/expected/quantifiers/large_range_warning.rs:15:13

Testing

  • large_range_warning.rs — expected test with 3 harnesses:
    • check_unbounded_forall_warns: unbounded forall!(|i| ...), verifies warning is emitted
    • check_unbounded_exists_warns: unbounded exists!(|i| ...), verifies warning is emitted
    • check_small_forall_no_warn: range of 10, verifies no warning (absence of output is intentional)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

@feliperodri feliperodri added this to the Contracts milestone Apr 19, 2026
@feliperodri feliperodri added [C] Feature / Enhancement A new feature request or enhancement to an existing feature. Z-Contracts Issue related to code contracts labels Apr 19, 2026
@github-actions github-actions Bot added Z-EndToEndBenchCI Tag a PR to run benchmark CI Z-CompilerBenchCI Tag a PR to run benchmark CI labels Apr 19, 2026
@feliperodri feliperodri force-pushed the warn-unbounded-quantifiers-sat branch 4 times, most recently from 814d5ef to 0f3e041 Compare April 19, 2026 18:50
@feliperodri feliperodri marked this pull request as ready for review April 19, 2026 18:50
@feliperodri feliperodri requested a review from a team as a code owner April 19, 2026 18:50
@feliperodri feliperodri force-pushed the warn-unbounded-quantifiers-sat branch 4 times, most recently from 1fbc451 to eb1297c Compare April 19, 2026 19:16
@feliperodri feliperodri force-pushed the warn-unbounded-quantifiers-sat branch 2 times, most recently from 1e66198 to a1cf899 Compare April 22, 2026 19:17
… ranges

SAT solvers (the default backend) expand quantifiers into one term per
value in the range. Unbounded quantifiers (forall!(|i| ...) which expand
over all 2^64 usize values) cause silent memory exhaustion or divergence
with no diagnostic.

This change:

- Adds warn_large_quantifier_range() in hooks.rs that checks if both
  quantifier bounds are compile-time integer constants and warns when
  the range exceeds 1000 values. For very large ranges (> 2^32), the
  message shows "unbounded (~2^64)" instead of the raw number.

- Adds unwrap_to_constant() that resolves typecasts and symbol table
  references to extract integer constants, with a depth limit of 5
  to guard against cycles.

- Adds an expected test (large_range_warning.rs) with 3 harnesses
  covering unbounded forall, unbounded exists, and a small range
  that should not warn.

Known limitation: bounded quantifiers (forall!(|i in (0, N)| ...)) use
let bindings in the macro for type coercion, which hides constants from
codegen. The warning currently only fires for unbounded quantifiers.

The warning suggests using tighter bounds or switching to an SMT solver
(#[kani::solver(z3)] or --solver z3).
@feliperodri feliperodri force-pushed the warn-unbounded-quantifiers-sat branch from a1cf899 to 6854cca Compare April 22, 2026 19:22
@feliperodri feliperodri enabled auto-merge April 22, 2026 19:23
@feliperodri feliperodri added this pull request to the merge queue Apr 22, 2026
Merged via the queue into model-checking:main with commit 6bfc273 Apr 22, 2026
33 of 34 checks passed
@feliperodri feliperodri deleted the warn-unbounded-quantifiers-sat branch April 22, 2026 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[C] Feature / Enhancement A new feature request or enhancement to an existing feature. Z-CompilerBenchCI Tag a PR to run benchmark CI Z-Contracts Issue related to code contracts Z-EndToEndBenchCI Tag a PR to run benchmark CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants