-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR introduces an initial implementation for the `autoharness` subcommand and a book chapter describing the feature. I recommend reading the book chapter before reviewing the code (or proceeding further in this PR description). ## Callouts `--harness` is to manual harnesses what `--include-function` and `--exclude-function` are to autoharness; both allow the user to filter which harnesses/functions get verified. Their implementation is different, however--`--harness` is a driver-only flag, i.e., we still compile every harness, but then only call CBMC on the ones specified in `--harness`. `--include-function` and `--exclude-function` get passed to the compiler. I made this design choice to try to be more aggressive about improving compiler performance--if a user only asks to verify one function and we go try to codegen a thousand, the compiler will take much longer than it needs to. I thought this more aggressive optimization was warranted given that crates are likely to have far many more functions eligible for autoverification than manual Kani harnesses. (See also the limitations in the book chapter). ## Testing Besides the new tests in this PR, I also ran against [s2n-quic](https://github.com/aws/s2n-quic) to confirm that the subcommand works on larger crates. Towards #3832 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
- Loading branch information
1 parent
4f78926
commit 8b2ec77
Showing
55 changed files
with
1,516 additions
and
101 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Automatic Harness Generation | ||
|
||
Recall the harness for `estimate_size` that we wrote in [First Steps](../../tutorial-first-steps.md): | ||
```rust | ||
{{#include ../../tutorial/first-steps-v1/src/lib.rs:kani}} | ||
``` | ||
|
||
This harness first declares a local variable `x` using `kani::any()`, then calls `estimate_size` with argument `x`. | ||
Many proof harnesses follow this predictable format—to verify a function `foo`, we create arbitrary values for each of `foo`'s arguments, then call `foo` on those arguments. | ||
|
||
The `autoharness` subcommand leverages this observation to automatically generate and run harnesses. | ||
Kani scans the crate for functions whose arguments all implement the `kani::Arbitrary` trait, generates harnesses for them, then runs them. | ||
These harnesses are internal to Kani--i.e., Kani does not make any changes to your source code. | ||
|
||
## Usage | ||
Run either: | ||
``` | ||
# cargo kani autoharness -Z unstable-options | ||
``` | ||
or | ||
``` | ||
# kani autoharness -Z unstable-options <FILE> | ||
``` | ||
|
||
If Kani detects that all of a function `foo`'s arguments implement `kani::Arbitrary`, it will generate and run a `#[kani::proof]` harness, which prints: | ||
|
||
``` | ||
Autoharness: Checking function foo against all possible inputs... | ||
<VERIFICATION RESULTS> | ||
``` | ||
|
||
However, if Kani detects that `foo` has a [contract](./contracts.md), it will instead generate a `#[kani::proof_for_contract]` harness and verify the contract: | ||
``` | ||
Autoharness: Checking function foo's contract against all possible inputs... | ||
<VERIFICATION RESULTS> | ||
``` | ||
|
||
Kani generates and runs these harnesses internally—the user only sees the verification results. | ||
|
||
The `autoharness` subcommand has options `--include-function` and `--exclude-function` to include and exclude particular functions. | ||
These flags look for partial matches against the fully qualified name of a function. | ||
|
||
For example, if a module `my_module` has many functions, but we are only interested in `my_module::foo` and `my_module::bar`, we can run: | ||
``` | ||
cargo run autoharness -Z unstable-options --include-function foo include-function bar | ||
``` | ||
To exclude `my_module` entirely, run: | ||
``` | ||
cargo run autoharness -Z unstable-options --exclude-function my_module | ||
``` | ||
|
||
## Example | ||
Using the `estimate_size` example from [First Steps](../../tutorial-first-steps.md) again: | ||
```rust | ||
{{#include ../../tutorial/first-steps-v1/src/lib.rs:code}} | ||
``` | ||
|
||
We get: | ||
|
||
``` | ||
# cargo kani autoharness -Z unstable-options | ||
Autoharness: Checking function estimate_size against all possible inputs... | ||
RESULTS: | ||
Check 3: estimate_size.assertion.1 | ||
- Status: FAILURE | ||
- Description: "Oh no, a failing corner case!" | ||
[...] | ||
Verification failed for - estimate_size | ||
Complete - 0 successfully verified functions, 1 failures, 1 total. | ||
``` | ||
|
||
## Request for comments | ||
This feature is experimental and is therefore subject to change. | ||
If you have ideas for improving the user experience of this feature, | ||
please add them to [this GitHub issue](https://github.com/model-checking/kani/issues/3832). | ||
|
||
## Limitations | ||
Kani will only generate an automatic harness for a function if it can determine that all of the function's arguments implement Arbitrary. | ||
It does not attempt to derive/implement Arbitrary for any types, even if those types could implement Arbitrary. | ||
|
||
If a function contains a loop with a loop contract, Kani will detect the presence of a loop contract and verify that contract. | ||
If, however, the loop does not have a contract, then there is currently no way to specify an unwinding bound for the function, meaning that Kani may hang as it tries to unwind the loop. | ||
We recommend using the `--exclude-function` option to exclude any functions that have this issue (or `--harness-timeout` to bail after attempting verification for some amount of time). |
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
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
Oops, something went wrong.