forked from model-checking/kani
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
16a9b37
commit e46bb3a
Showing
13 changed files
with
182 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...rgo_autoverify_contracts_fixme/Cargo.toml → ...pre/cargo_autoverify_contracts/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
19 changes: 19 additions & 0 deletions
19
tests/script-based-pre/cargo_autoverify_contracts/contracts.expected
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Checking function should_fail::max against all possible inputs... | ||
assertion\ | ||
- Status: FAILURE\ | ||
- Description: "|result : &u32| *result == x" | ||
|
||
Checking function should_pass::has_loop_contract against all possible inputs... | ||
should_pass::has_loop_contract.assertion\ | ||
- Status: SUCCESS\ | ||
- Description: "assertion failed: x == 2" | ||
|
||
Checking function should_pass::has_recursion_gcd against all possible inputs... | ||
assertion\ | ||
- Status: SUCCESS\ | ||
- Description: "|result : &u8| *result != 0 && x % *result == 0 && y % *result == 0" | ||
|
||
Checking function should_pass::div against all possible inputs... | ||
|
||
Verification failed for - should_fail::max | ||
Complete - 3 successfully verified harnesses, 1 failures, 4 total. |
9 changes: 9 additions & 0 deletions
9
tests/script-based-pre/cargo_autoverify_contracts/contracts.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/usr/bin/env bash | ||
# Copyright Kani Contributors | ||
# SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
cargo kani autoverify -Z unstable-options -Z function-contracts -Z loop-contracts | ||
# We expect verification to fail, so the above command will produce an exit status of 1 | ||
# However, we don't want the test to fail because of that exit status; we only want it to fail if the expected file doesn't match | ||
# So, exit with a status code of 0 explicitly. | ||
exit 0; |
50 changes: 50 additions & 0 deletions
50
tests/script-based-pre/cargo_autoverify_contracts/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
// Test that the autoverify subcommand correctly verifies contracts, | ||
// i.e., that it detects the presence of a contract and generates a contract | ||
// harness instead of a standard harness. | ||
|
||
#![feature(stmt_expr_attributes)] | ||
#![feature(proc_macro_hygiene)] | ||
|
||
mod should_pass { | ||
#[kani::requires(divisor != 0)] | ||
fn div(dividend: u32, divisor: u32) -> u32 { | ||
dividend / divisor | ||
} | ||
|
||
#[kani::requires(x != 0 && y != 0)] | ||
#[kani::ensures(|result : &u8| *result != 0 && x % *result == 0 && y % *result == 0)] | ||
#[kani::recursion] | ||
fn has_recursion_gcd(x: u8, y: u8) -> u8 { | ||
let mut max = x; | ||
let mut min = y; | ||
if min > max { | ||
let val = max; | ||
max = min; | ||
min = val; | ||
} | ||
|
||
let res = max % min; | ||
if res == 0 { min } else { has_recursion_gcd(min, res) } | ||
} | ||
|
||
fn has_loop_contract() { | ||
let mut x: u8 = kani::any_where(|i| *i >= 2); | ||
|
||
#[kani::loop_invariant(x >= 2)] | ||
while x > 2 { | ||
x = x - 1; | ||
} | ||
|
||
assert!(x == 2); | ||
} | ||
} | ||
|
||
mod should_fail { | ||
#[kani::ensures(|result : &u32| *result == x)] | ||
fn max(x: u32, y: u32) -> u32 { | ||
if x > y { x } else { y } | ||
} | ||
} |
1 change: 0 additions & 1 deletion
1
tests/script-based-pre/cargo_autoverify_contracts_fixme/contracts.expected
This file was deleted.
Oops, something went wrong.
5 changes: 0 additions & 5 deletions
5
tests/script-based-pre/cargo_autoverify_contracts_fixme/contracts.sh
This file was deleted.
Oops, something went wrong.
16 changes: 0 additions & 16 deletions
16
tests/script-based-pre/cargo_autoverify_contracts_fixme/src/lib.rs
This file was deleted.
Oops, something went wrong.
1 change: 0 additions & 1 deletion
1
tests/script-based-pre/cargo_autoverify_loops_fixme/loops.expected
This file was deleted.
Oops, something went wrong.
37 changes: 24 additions & 13 deletions
37
tests/script-based-pre/cargo_autoverify_loops_fixme/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,39 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// kani-flags: -Zautomatic-harnesses | ||
|
||
#![feature(stmt_expr_attributes)] | ||
#![feature(proc_macro_hygiene)] | ||
|
||
// Test that automatic harnesses terminate on functions with loops. | ||
|
||
// Since foo()'s arguments implement Arbitrary, we will attempt to verify it, | ||
// and enter an infinite loop. | ||
// Instead, we should just skip this function, perhaps printing a message to the user that we skipped it. | ||
// Unclear what the best solution to this problem is; perhaps this is just a known limitation | ||
// and the user needs to specify some command line flag to skip this function, | ||
// or we can conservatively skip functions with loops that don't have loop contracts. | ||
fn infinite_loop() { | ||
loop {} | ||
} | ||
|
||
// Shouldn't skip this function -- it has a loop, but since it also has a loop contract, | ||
// we can generate a contract harness for it and be assured that the proof will terminate. | ||
fn has_loop_contract() { | ||
let mut x: u8 = kani::any_where(|i| *i >= 2); | ||
/// Euclid's algorithm for calculating the GCD of two numbers | ||
#[kani::requires(x != 0 && y != 0)] | ||
#[kani::ensures(|result : &u8| *result != 0 && x % *result == 0 && y % *result == 0)] | ||
fn gcd(mut x: u8, mut y: u8) -> u8 { | ||
(x, y) = (if x > y { x } else { y }, if x > y { y } else { x }); | ||
loop { | ||
let res = x % y; | ||
if res == 0 { | ||
return y; | ||
} | ||
|
||
#[kani::loop_invariant(x >= 2)] | ||
while x > 2 { | ||
x = x - 1; | ||
x = y; | ||
y = res; | ||
} | ||
} | ||
|
||
assert!(x == 2); | ||
// Since we can specify an unwinding bound in a manual harness, | ||
// the proof will terminate. | ||
// Automatic harnesses, however, do not support unwinding bounds, | ||
// so the proof does not terminate. | ||
#[kani::proof_for_contract(gcd)] | ||
#[kani::unwind(12)] | ||
fn gcd_harness() { | ||
gcd(kani::any(), kani::any()); | ||
} |