Skip to content

Warn when quantifier range exceeds SAT solver threshold#4579

Open
feliperodri wants to merge 1 commit intomodel-checking:mainfrom
feliperodri:warn-unbounded-quantifiers-sat
Open

Warn when quantifier range exceeds SAT solver threshold#4579
feliperodri wants to merge 1 commit intomodel-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 3 times, most recently from c50cbc8 to 1fbc451 Compare April 19, 2026 19:13
… 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 1fbc451 to eb1297c Compare April 19, 2026 19:16
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.

1 participant