|
| 1 | +# Debugging verification failures |
| 2 | + |
| 3 | +When the result of a certain check comes back as a `FAILURE`, |
| 4 | +Kani offers different options to help debug: |
| 5 | +* `--concrete-playback`. This _experimental_ feature generates a Rust unit test case that plays back a failing |
| 6 | +proof harness using a concrete counterexample. |
| 7 | +* `--visualize`. This feature generates an HTML text-based trace that |
| 8 | +enumerates the execution steps leading to the check failure. |
| 9 | + |
| 10 | +## Concrete playback |
| 11 | + |
| 12 | +This section describes the concrete playback feature in more detail. |
| 13 | + |
| 14 | +### Setup |
| 15 | + |
| 16 | +The Kani library needs to be linked as a dev dependency to the crate you're trying to debug. |
| 17 | +This requires adding the following lines to your `Cargo.toml` file, |
| 18 | +which differ depending on what version of the Kani library you would like to use: |
| 19 | +* The latest version: |
| 20 | +```toml |
| 21 | +[dev-dependencies] |
| 22 | +kani = { git = "https://github.com/model-checking/kani", features = ["concrete_playback"] } |
| 23 | +``` |
| 24 | +* A specific version of the Kani library (v0.9+) that's already downloaded: |
| 25 | +```toml |
| 26 | +[dev-dependencies] |
| 27 | +kani = { path = "{path_to_kani_root}/library/kani", features = ["concrete_playback"] } |
| 28 | +``` |
| 29 | + |
| 30 | +### Usage |
| 31 | + |
| 32 | +In order to enable this feature, run Kani with the `--enable-unstable --concrete-playback=[print|inplace]` flag. |
| 33 | +After getting a verification failure, Kani will generate a Rust unit test case that plays back a failing |
| 34 | +proof harness with a concrete counterexample. |
| 35 | +The concrete playback modes mean the following: |
| 36 | +* `print`: Kani will just print the unit test to stdout. |
| 37 | +You will then need to copy this unit test into the same module as your proof harness. |
| 38 | +* `inplace`: Kani will automatically copy the unit test into your source code. |
| 39 | +Before running this mode, you might find it helpful to have your existing code committed to `git`. |
| 40 | +That way, you can easily remove the unit test with `git revert`. |
| 41 | +Note that Kani will not copy the unit test into your source code if it detects |
| 42 | +that the exact same test already exists. |
| 43 | + |
| 44 | +After the unit test is in your source code, you can run it with `cargo test`. |
| 45 | +To debug it, there are a couple of options: |
| 46 | +* If you have certain IDEs, there are extensions (e.g., `rust-analyzer` for `VS Code`) |
| 47 | +that support UI elements like a `Run Test | Debug` button next to all unit tests. |
| 48 | +* Otherwise, you can debug the unit test on the command line. |
| 49 | +To do this, you first run `cargo test {unit_test_func_name}`. |
| 50 | +The output from this will have a line in the beginning like `Running unittests {files} ({binary})`. |
| 51 | +You can then debug the binary with tools like `rust-gdb` or `lldb`. |
| 52 | + |
| 53 | +### Example |
| 54 | + |
| 55 | +Running `kani --harness proof_harness --enable-unstable --concrete-playback=print` on the following source file: |
| 56 | +```rust |
| 57 | +#[kani::proof] |
| 58 | +fn proof_harness() { |
| 59 | + let a: u8 = kani::any(); |
| 60 | + let b: u16 = kani::any(); |
| 61 | + assert!(a / 2 * 2 == a && |
| 62 | + b / 2 * 2 == b); |
| 63 | +} |
| 64 | +``` |
| 65 | +yields this concrete playback Rust unit test: |
| 66 | +```rust |
| 67 | +#[test] |
| 68 | +fn kani_concrete_playback_proof_harness_16220658101615121791() { |
| 69 | + let concrete_vals: Vec<Vec<u8>> = vec![ |
| 70 | + // 133 |
| 71 | + vec![133], |
| 72 | + // 35207 |
| 73 | + vec![135, 137], |
| 74 | + ]; |
| 75 | + kani::concrete_playback_run(concrete_vals, proof_harness); |
| 76 | +} |
| 77 | +``` |
| 78 | +Here, `133` and `35207` are the concrete values that, when substituted for `a` and `b`, |
| 79 | +cause an assertion failure. |
| 80 | +`vec![135, 137]` is the byte array representation of `35207`. |
| 81 | + |
| 82 | +### Common issues |
| 83 | + |
| 84 | +* `error[E0425]: cannot find function x in this scope`: |
| 85 | +this is usually caused by having `#[cfg(kani)]` somewhere in the control flow path of the user's proof harness. |
| 86 | +To fix this, remove `#[cfg(kani)]` from those paths. |
| 87 | + |
| 88 | +### Request for comments |
| 89 | + |
| 90 | +This feature is experimental and is therefore subject to change. |
| 91 | +If you have ideas for improving the user experience of this feature, |
| 92 | +please add them to [this GitHub issue](https://github.com/model-checking/kani/issues/1536). |
| 93 | +We are tracking the existing feature requests in |
| 94 | +[this GitHub milestone](https://github.com/model-checking/kani/milestone/10). |
| 95 | + |
| 96 | +### Limitations |
| 97 | + |
| 98 | +* This feature does not generate unit tests for failing non-panic checks (e.g., UB checks). |
| 99 | +This is because checks would not trigger runtime errors during concrete playback. |
| 100 | +Kani generates warning messages for this. |
| 101 | +* This feature does not support generating unit tests for multiple assertion failures within the same harness. |
| 102 | +This limitation might be removed in the future. |
| 103 | +Kani generates warning messages for this. |
| 104 | +* This feature requires that you do not change your code or runtime configurations between when Kani generates the unit test and when you run it. |
| 105 | +For instance, if you linked with library A during unit test generation and library B during unit test play back, |
| 106 | +that might cause unintended errors in the unit test counterexample. |
| 107 | +Kani currently has no way to detect this issue. |
0 commit comments