Skip to content

Commit 68cb4ee

Browse files
authored
Autoharness Misc. Improvements (#3922)
Follow up to #3874 implementing the features requested during review. Hopefully reviewing commit-by-commit makes the size manageable (most of the changes come from the additional metadata logging) but happy to split this into multiple PRs if not. The list below maps each commit to the review comment on #3874 that inspired it. - 8685925: #3874 (comment) - f060d66: #3874 (comment) - 7a7f654: #3874 (comment) - 4f3add8: #3874 (comment) - 212b0ff: #3874 (comment) - f105a9c: #3874 (review) and - 6a8dc61: #3874 (review) - 6f946bb and 6997afb: #3874 (comment) 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.
1 parent 9ea1f38 commit 68cb4ee

File tree

38 files changed

+742
-215
lines changed

38 files changed

+742
-215
lines changed

docs/src/reference/experimental/autoharness.md

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ Recall the harness for `estimate_size` that we wrote in [First Steps](../../tuto
88
This harness first declares a local variable `x` using `kani::any()`, then calls `estimate_size` with argument `x`.
99
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.
1010

11-
The `autoharness` subcommand leverages this observation to automatically generate and run harnesses.
11+
The `autoharness` subcommand leverages this observation to automatically generate harnesses and run Kani against them.
1212
Kani scans the crate for functions whose arguments all implement the `kani::Arbitrary` trait, generates harnesses for them, then runs them.
13-
These harnesses are internal to Kani--i.e., Kani does not make any changes to your source code.
13+
These harnesses are internal to Kanii.e., Kani does not make any changes to your source code.
1414

1515
## Usage
1616
Run either:
1717
```
18-
# cargo kani autoharness -Z unstable-options
18+
# cargo kani autoharness -Z autoharness
1919
```
2020
or
2121
```
22-
# kani autoharness -Z unstable-options <FILE>
22+
# kani autoharness -Z autoharness <FILE>
2323
```
2424

2525
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:
@@ -42,11 +42,11 @@ These flags look for partial matches against the fully qualified name of a funct
4242

4343
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:
4444
```
45-
cargo run autoharness -Z unstable-options --include-function foo include-function bar
45+
cargo run autoharness -Z autoharness --include-function foo --include-function bar
4646
```
4747
To exclude `my_module` entirely, run:
4848
```
49-
cargo run autoharness -Z unstable-options --exclude-function my_module
49+
cargo run autoharness -Z autoharness --exclude-function my_module
5050
```
5151

5252
## Example
@@ -58,7 +58,7 @@ Using the `estimate_size` example from [First Steps](../../tutorial-first-steps.
5858
We get:
5959

6060
```
61-
# cargo kani autoharness -Z unstable-options
61+
# cargo kani autoharness -Z autoharness
6262
Autoharness: Checking function estimate_size against all possible inputs...
6363
RESULTS:
6464
Check 3: estimate_size.assertion.1
@@ -76,9 +76,44 @@ If you have ideas for improving the user experience of this feature,
7676
please add them to [this GitHub issue](https://github.com/model-checking/kani/issues/3832).
7777

7878
## Limitations
79+
### Arguments Implementing Arbitrary
7980
Kani will only generate an automatic harness for a function if it can determine that all of the function's arguments implement Arbitrary.
8081
It does not attempt to derive/implement Arbitrary for any types, even if those types could implement Arbitrary.
82+
For example, imagine a user defines `struct MyStruct { x: u8, y: u8}`, but does not derive or implement Arbitrary for `MyStruct`.
83+
Kani does not attempt to add such derivations itself, so it will not generate a harness for a function that takes `MyStruct` as input.
8184

85+
### Generic Functions
86+
The current implementation does not generate harnesses for generic functions.
87+
For example, given:
88+
```rust
89+
fn foo<T: Eq>(x: T, y: T) {
90+
if x == y {
91+
panic!("x and y are equal");
92+
}
93+
}
94+
```
95+
Kani would report that no functions were eligible for automatic harness generation.
96+
97+
If, however, some caller of `foo` is eligible for an automatic harness, then a monomorphized version of `foo` may still be reachable during verification.
98+
For instance, if we add `main`:
99+
```rust
100+
fn main() {
101+
let x: u8 = 2;
102+
let y: u8 = 2;
103+
foo(x, y);
104+
}
105+
```
106+
and run the autoharness subcommand, we get:
107+
```
108+
Autoharness: Checking function main against all possible inputs...
109+
110+
Failed Checks: x and y are equal
111+
File: "src/lib.rs", line 3, in foo::<u8>
112+
113+
VERIFICATION:- FAILED
114+
```
115+
116+
### Loop Contracts
82117
If a function contains a loop with a loop contract, Kani will detect the presence of a loop contract and verify that contract.
83118
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.
84119
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).

kani-compiler/src/args.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,14 @@ pub struct Arguments {
9191
/// Print the final LLBC file to stdout.
9292
#[clap(long)]
9393
pub print_llbc: bool,
94-
/// If we are running the autoharness subcommand, the functions to autoharness
95-
#[arg(long = "autoharness-include-function", num_args(1))]
94+
/// If we are running the autoharness subcommand, the functions to include
95+
#[arg(
96+
long = "autoharness-include-function",
97+
num_args(1),
98+
conflicts_with = "autoharness_excluded_functions"
99+
)]
96100
pub autoharness_included_functions: Vec<String>,
97-
/// If we are running the autoharness subcommand, the functions to exclude from autoverification
101+
/// If we are running the autoharness subcommand, the functions to exclude
98102
#[arg(long = "autoharness-exclude-function", num_args(1))]
99103
pub autoharness_excluded_functions: Vec<String>,
100104
}

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ impl GotoCodegenResults {
613613
// removes any contracts logic for ReachabilityType::Test or ReachabilityType::PubFns,
614614
// which are the two ReachabilityTypes under which the compiler calls this function.
615615
contracted_functions: vec![],
616+
autoharness_skipped_fns: None,
616617
}
617618
}
618619

kani-compiler/src/kani_middle/attributes.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,17 @@ impl<'tcx> KaniAttributes<'tcx> {
310310
})
311311
}
312312

313+
// Is this a function inserted by Kani instrumentation?
314+
pub fn is_kani_instrumentation(&self) -> bool {
315+
self.fn_marker().is_some() || self.is_contract_generated()
316+
}
317+
318+
// Is this a contract-generated function?
319+
// Note that this function currently always returns false because of https://github.com/model-checking/kani/issues/3921
320+
fn is_contract_generated(&self) -> bool {
321+
self.map.contains_key(&KaniAttributeKind::IsContractGenerated)
322+
}
323+
313324
/// Return a function marker if any.
314325
pub fn fn_marker(&self) -> Option<Symbol> {
315326
self.attribute_value(KaniAttributeKind::FnMarker)

0 commit comments

Comments
 (0)