Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions kani-driver/src/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ pub struct VerificationArgs {
#[arg(long)]
pub harness_timeout: Option<Timeout>,

/// Verification process will stop as soon as one of the harnesses fails.
#[arg(long)]
pub fail_fast: bool,

/// Arguments to pass down to Cargo
#[command(flatten)]
pub cargo: CargoCommonArgs,
Expand Down
47 changes: 41 additions & 6 deletions kani-driver/src/harness_runner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use anyhow::{Result, bail};
use anyhow::{Error, Result, bail};
use kani_metadata::{ArtifactType, HarnessMetadata};
use rayon::prelude::*;
use std::fs::File;
Expand Down Expand Up @@ -29,11 +29,26 @@ pub(crate) struct HarnessRunner<'sess, 'pr> {

/// The result of checking a single harness. This both hangs on to the harness metadata
/// (as a means to identify which harness), and provides that harness's verification result.

pub(crate) struct HarnessResult<'pr> {
pub harness: &'pr HarnessMetadata,
pub result: VerificationResult,
}

#[derive(Debug)]
struct ErrorImpl {
pub index_to_failing_harness: usize,
pub result: VerificationResult,
}

impl std::error::Error for ErrorImpl {}

impl std::fmt::Display for ErrorImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "harness failed")
}
}

impl<'pr> HarnessRunner<'_, 'pr> {
/// Given a [`HarnessRunner`] (to abstract over how these harnesses were generated), this runs
/// the proof-checking process for each harness in `harnesses`.
Expand All @@ -55,7 +70,8 @@ impl<'pr> HarnessRunner<'_, 'pr> {
let results = pool.install(|| -> Result<Vec<HarnessResult<'pr>>> {
sorted_harnesses
.par_iter()
.map(|harness| -> Result<HarnessResult<'pr>> {
.enumerate()
.map(|(idx, harness)| -> Result<HarnessResult<'pr>> {
let goto_file =
self.project.get_harness_artifact(&harness, ArtifactType::Goto).unwrap();

Expand All @@ -66,12 +82,31 @@ impl<'pr> HarnessRunner<'_, 'pr> {
}

let result = self.sess.check_harness(goto_file, harness)?;
Ok(HarnessResult { harness, result })
if self.sess.args.fail_fast && result.status == VerificationStatus::Failure {
return Err(Error::new(ErrorImpl {
index_to_failing_harness: idx,
result: result,
}));
} else {
return Ok(HarnessResult { harness, result });
}
})
.collect::<Result<Vec<_>>>()
})?;

Ok(results)
});
match results {
Ok(results) => Ok(results),
Err(err) => {
if err.is::<ErrorImpl>() {
let failed = err.downcast::<ErrorImpl>().unwrap();
Ok(vec![HarnessResult {
harness: sorted_harnesses[failed.index_to_failing_harness],
result: failed.result,
}])
} else {
Err(err)
}
}
}
}

/// Return an error if the user is trying to verify a harness with stubs without enabling the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Complete - 0 successfully verified harnesses, 1 failures, 1 total.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT
// kani-flags: --fail-fast
//! Ensure that the verification process stops as soon as one of the harnesses fails.

mod tests {
#[kani::proof]
fn test_01_fail() {
assert!(false, "First failure");
}

#[kani::proof]
fn test_02_fail() {
assert!(false, "Second failure");
}

#[kani::proof]
fn test_03_fail() {
assert!(false, "Third failure");
}

#[kani::proof]
fn test_04_fail() {
assert!(false, "Fourth failure");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Complete - 0 successfully verified harnesses, 1 failures, 1 total.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT
// kani-flags: --fail-fast -Z unstable-options --jobs 4 --output-format=terse
//! Ensure that the verification process stops as soon as one of the harnesses fails.
//! This test runs on 4 parallel threads. Stops verification as soon as a harness on any of the threads fails.

mod tests {
#[kani::proof]
fn test_01_fail() {
assert!(false, "First failure");
}

#[kani::proof]
fn test_02_fail() {
assert!(false, "Second failure");
}

#[kani::proof]
fn test_03_fail() {
assert!(false, "Third failure");
}

#[kani::proof]
fn test_04_fail() {
assert!(false, "Fourth failure");
}

#[kani::proof]
fn test_05_fail() {
assert!(false, "Fifth failure");
}

#[kani::proof]
fn test_06_fail() {
assert!(false, "Sixth failure");
}

#[kani::proof]
fn test_07_fail() {
assert!(false, "Seventh failure");
}

#[kani::proof]
fn test_08_fail() {
assert!(false, "Eighth failure");
}

#[kani::proof]
fn test_09_fail() {
assert!(false, "Ninth failure");
}

#[kani::proof]
fn test_10_fail() {
assert!(false, "Tenth failure");
}
}
Loading