Skip to content

Commit 7f232fe

Browse files
authored
Enable concrete playback for satisfiable cover properties (rust-lang#2134)
1 parent f635f7b commit 7f232fe

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

kani-driver/src/call_cbmc.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub struct VerificationResult {
3838
pub exit_status: i32,
3939
/// The runtime duration of this CBMC invocation.
4040
pub runtime: Duration,
41+
/// Whether concrete playback generated a test
42+
pub generated_concrete_test: bool,
4143
}
4244

4345
impl KaniSession {
@@ -51,7 +53,8 @@ impl KaniSession {
5153

5254
let start_time = Instant::now();
5355

54-
let verification_results = if self.args.output_format == crate::args::OutputFormat::Old {
56+
let mut verification_results = if self.args.output_format == crate::args::OutputFormat::Old
57+
{
5558
if self.run_terminal(cmd).is_err() {
5659
VerificationResult::mock_failure()
5760
} else {
@@ -80,7 +83,7 @@ impl KaniSession {
8083
}
8184
};
8285

83-
self.gen_and_add_concrete_playback(harness, &verification_results)?;
86+
self.gen_and_add_concrete_playback(harness, &mut verification_results)?;
8487
Ok(verification_results)
8588
}
8689

@@ -204,6 +207,7 @@ impl VerificationResult {
204207
results: Some(results),
205208
exit_status: output.process_status,
206209
runtime,
210+
generated_concrete_test: false,
207211
}
208212
} else {
209213
// We never got results from CBMC - something went wrong (e.g. crash) so it's failure
@@ -213,6 +217,7 @@ impl VerificationResult {
213217
results: None,
214218
exit_status: output.process_status,
215219
runtime,
220+
generated_concrete_test: false,
216221
}
217222
}
218223
}
@@ -224,6 +229,7 @@ impl VerificationResult {
224229
results: None,
225230
exit_status: 42, // on success, exit code is ignored, so put something weird here
226231
runtime: Duration::from_secs(0),
232+
generated_concrete_test: false,
227233
}
228234
}
229235

@@ -237,6 +243,7 @@ impl VerificationResult {
237243
// so again use something weird:
238244
exit_status: 42,
239245
runtime: Duration::from_secs(0),
246+
generated_concrete_test: false,
240247
}
241248
}
242249

kani-driver/src/concrete_playback.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! generating concrete playback unit tests, and adding them to the user's source code.
66
77
use crate::args::ConcretePlaybackMode;
8-
use crate::call_cbmc::{VerificationResult, VerificationStatus};
8+
use crate::call_cbmc::VerificationResult;
99
use crate::session::KaniSession;
1010
use anyhow::{Context, Result};
1111
use concrete_vals_extractor::{extract_harness_values, ConcreteVal};
@@ -23,17 +23,13 @@ impl KaniSession {
2323
pub fn gen_and_add_concrete_playback(
2424
&self,
2525
harness: &HarnessMetadata,
26-
verification_result: &VerificationResult,
26+
verification_result: &mut VerificationResult,
2727
) -> Result<()> {
2828
let playback_mode = match self.args.concrete_playback {
2929
Some(playback_mode) => playback_mode,
3030
None => return Ok(()),
3131
};
3232

33-
if verification_result.status == VerificationStatus::Success {
34-
return Ok(());
35-
}
36-
3733
if let Some(result_items) = &verification_result.results {
3834
match extract_harness_values(result_items) {
3935
None => println!(
@@ -71,6 +67,7 @@ impl KaniSession {
7167
.expect("Failed to modify source code");
7268
}
7369
}
70+
verification_result.generated_concrete_test = true;
7471
}
7572
}
7673
}
@@ -309,7 +306,8 @@ mod concrete_vals_extractor {
309306
/// This will return None if the failure is not related to a user assertion.
310307
pub fn extract_harness_values(result_items: &[Property]) -> Option<Vec<ConcreteVal>> {
311308
let mut failures = result_items.iter().filter(|prop| {
312-
prop.property_class() == "assertion" && prop.status == CheckStatus::Failure
309+
(prop.property_class() == "assertion" && prop.status == CheckStatus::Failure)
310+
|| (prop.property_class() == "cover" && prop.status == CheckStatus::Satisfied)
313311
});
314312

315313
// Process the first assertion failure.

kani-driver/src/harness_runner.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,10 @@ impl KaniSession {
116116
let failing = failures.len();
117117
let total = succeeding + failing;
118118

119-
if self.args.concrete_playback.is_some() && !self.args.quiet && failures.is_empty() {
119+
if self.args.concrete_playback.is_some()
120+
&& !self.args.quiet
121+
&& results.iter().all(|r| !r.result.generated_concrete_test)
122+
{
120123
println!(
121124
"INFO: The concrete playback feature never generated unit tests because there were no failing harnesses."
122125
)
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
1 of 1 cover properties satisfied
2+
VERIFICATION:- SUCCESSFUL
3+
4+
Concrete playback
5+
```
6+
#[test]
7+
fn kani_concrete_playback_harness
8+
let concrete_vals: Vec<Vec<u8>> = vec![
9+
// 1
10+
vec![1, 0, 0, 0]
11+
];
12+
kani::concrete_playback_run(concrete_vals, harness);
13+
}
14+
```
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// kani-flags: --enable-unstable --concrete-playback=print
5+
6+
#[kani::proof]
7+
pub fn harness() {
8+
let x: u32 = kani::any();
9+
kani::cover!(x != 0 && x / 2 == 0);
10+
}

0 commit comments

Comments
 (0)