Skip to content

Commit ab7c438

Browse files
authored
Support bitwuzla, cvc5, z3 as solver attribute values (#4218)
Adds support for solver attribute values `bitwuzla`, `cvc5`, and `z3` to make CBMC use the corresponding SMT solver. Use Z3 for selected tests when running regression tests with the following rationale: The tests loop_assigns_for_vec.rs and assert-postconditions.rs previously required more than 8 GB of memory on Ubuntu/x86 and solved in 1:15 minutes and 25 seconds, respectively. When using Z3 as back-end solver, they complete in 35 and 2 seconds (2.5 GB and 150 MB), respectively. Use CVC5 for the test from issue #4226. We are not testing Bitwuzla support in CI at this point (though it has been confirmed to work locally), because Bitwuzla only releases binaries for some of our CI platforms, and we cannot even build Bitwuzla from source on Ubuntu 22.04 (meson is too old). Resolves: #3277 Resolves: #4226 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 9ef900f commit ab7c438

File tree

9 files changed

+68
-0
lines changed

9 files changed

+68
-0
lines changed

docs/src/build-from-source.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ In general, the following dependencies are required to build Kani from source.
1313
1. Cargo installed via [rustup](https://rustup.rs/)
1414
2. [CBMC](https://github.com/diffblue/cbmc) (latest release)
1515
3. [Kissat](https://github.com/arminbiere/kissat) (Release 4.0.1)
16+
3. [Z3](https://github.com/Z3Prover/z3)
17+
4. [cvc5](https://github.com/cvc5/cvc5)
1618

1719
Kani has been tested in [Ubuntu](#install-dependencies-on-ubuntu) and [macOS](##install-dependencies-on-macos) platforms.
1820

docs/src/reference/attributes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ At present, `<solver>` can be one of:
206206
- `minisat`: [MiniSat](http://minisat.se/).
207207
- `cadical` (default): [CaDiCaL](https://github.com/arminbiere/cadical).
208208
- `kissat`: [kissat](https://github.com/arminbiere/kissat).
209+
- `z3`: [Z3](https://github.com/Z3Prover/z3/).
210+
- `bitwuzla`: [Bitwuzla](https://github.com/bitwuzla/bitwuzla).
211+
- `cvc5`: [cvc5](https://github.com/cvc5/cvc5).
209212
- `bin="<SAT_SOLVER_BINARY>"`: A custom solver binary, `"<SAT_SOLVER_BINARY>"`, that must be in path.
210213

211214
### Example

kani-driver/src/call_cbmc.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,16 @@ impl KaniSession {
279279
};
280280

281281
match solver {
282+
CbmcSolver::Bitwuzla => {
283+
args.push("--bitwuzla".into());
284+
}
282285
CbmcSolver::Cadical => {
283286
args.push("--sat-solver".into());
284287
args.push("cadical".into());
285288
}
289+
CbmcSolver::Cvc5 => {
290+
args.push("--cvc5".into());
291+
}
286292
CbmcSolver::Kissat => {
287293
args.push("--external-sat-solver".into());
288294
args.push("kissat".into());
@@ -291,6 +297,9 @@ impl KaniSession {
291297
// Minisat is currently CBMC's default solver, so no need to
292298
// pass any arguments
293299
}
300+
CbmcSolver::Z3 => {
301+
args.push("--z3".into());
302+
}
294303
CbmcSolver::Binary(solver_binary) => {
295304
// Check if the specified binary exists in path
296305
if which::which(solver_binary).is_err() {

kani_metadata/src/cbmc_solver.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,24 @@ use strum_macros::{AsRefStr, EnumString, VariantNames};
1010
#[derive(Debug, Clone, AsRefStr, EnumString, VariantNames, PartialEq, Eq, Serialize, Deserialize)]
1111
#[strum(serialize_all = "snake_case")]
1212
pub enum CbmcSolver {
13+
/// Bitwuzla SMT solver
14+
Bitwuzla,
15+
1316
/// CaDiCaL which is available in CBMC as of version 5.77.0
1417
Cadical,
1518

19+
/// cvc5 SMT solver
20+
Cvc5,
21+
1622
/// The kissat solver that is included in the Kani bundle
1723
Kissat,
1824

1925
/// MiniSAT (CBMC's default solver)
2026
Minisat,
2127

28+
/// Z3 SMT solver
29+
Z3,
30+
2231
/// A solver binary variant whose argument gets passed to
2332
/// `--external-sat-solver`. The specified binary must exist in path.
2433
#[strum(disabled, serialize = "bin=<SAT_SOLVER_BINARY>")]

scripts/setup/macos/install_deps.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ brew update
1414
brew install python@3 || true
1515
brew link --overwrite python@3
1616

17+
# Install SMT solvers being used in regression tests
18+
brew install z3
19+
ARCH=$(uname -m)
20+
curl -L --remote-name https://github.com/cvc5/cvc5/releases/download/cvc5-1.3.0/cvc5-macOS-${ARCH}-static.zip
21+
sudo unzip -o -j -d /usr/local/bin cvc5-macOS-${ARCH}-static.zip cvc5-macOS-${ARCH}-static/bin/cvc5
22+
rm cvc5-macOS-${ARCH}-static.zip
23+
cvc5 --version
24+
1725
# Get the directory containing this script
1826
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
1927

scripts/setup/ubuntu/install_deps.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ DEPS=(
1616
gpg-agent
1717
make
1818
patch
19+
z3
1920
zlib1g
2021
zlib1g-dev
2122
)
@@ -30,6 +31,12 @@ sudo apt-get --yes update
3031

3132
sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --yes "${DEPS[@]}"
3233

34+
ARCH=$(uname -m)
35+
curl -L --remote-name https://github.com/cvc5/cvc5/releases/download/cvc5-1.3.0/cvc5-Linux-${ARCH}-static.zip
36+
sudo unzip -o -j -d /usr/local/bin cvc5-Linux-${ARCH}-static.zip cvc5-Linux-${ARCH}-static/bin/cvc5
37+
rm cvc5-Linux-${ARCH}-static.zip
38+
cvc5 --version
39+
3340
# Get the directory containing this script
3441
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
3542

tests/expected/function-contract/as-assertions/assert-postconditions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn add_one(add_one_ptr: &mut u32) {
2323
}
2424

2525
#[kani::proof_for_contract(add_three)]
26+
#[kani::solver(z3)]
2627
fn prove_add_three() {
2728
let mut i = kani::any();
2829
add_three(&mut i);

tests/expected/loop-contract/loop_assigns_for_vec.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::ptr;
1212
use std::ptr::slice_from_raw_parts;
1313

1414
#[kani::proof]
15+
#[kani::solver(z3)]
1516
fn main() {
1617
let mut i = 0;
1718
let a: [u8; 3] = kani::any();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: -Z quantifiers
4+
5+
// See https://github.com/model-checking/kani/issues/4226
6+
7+
#[kani::proof]
8+
#[kani::solver(cvc5)]
9+
fn main() {
10+
const N: usize = 100;
11+
let a: [i32; N] = kani::any();
12+
let i = kani::any();
13+
kani::assume(i < N - 1);
14+
kani::assume(kani::forall!(|j in (1, i)| a[j] < 10));
15+
kani::assume(a[i] < 10);
16+
assert!(kani::forall!(|j in (1, i+1)| a[j] < 10));
17+
}
18+
19+
#[kani::proof]
20+
fn bounded() {
21+
const N: usize = 100;
22+
let a: [i32; N] = kani::any();
23+
let i = 20;
24+
kani::assume(i < N - 1);
25+
kani::assume(kani::forall!(|j in (1, i)| a[j] < 10));
26+
kani::assume(a[i] < 10);
27+
assert!(kani::forall!(|j in (1, i+1)| a[j] < 10));
28+
}

0 commit comments

Comments
 (0)