Skip to content
Open
Changes from all 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
47 changes: 41 additions & 6 deletions tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,41 @@ impl TestCx<'_> {
}
}

/// Returns the per-test cargo target directory, after removing any leftover
/// contents so the build starts from a clean, reproducible state.
///
/// The target directory is persistent across regression runs and is reused
/// whenever a test is re-run (the compiletest stamp is derived from
/// `kani-compiler` and the library/compiler/driver source trees, so any
/// kani rebuild forces a re-run). A target directory left in a stale or
/// partially-built state -- for instance from a regression run that was
/// interrupted or OOM-killed mid-build, or built by an older
/// `kani-compiler` -- can make cargo treat a path-dependency crate as up to
/// date while its compiled artifact is missing or incompatible, producing
/// spurious `can't find crate` (E0463) errors that don't match the expected
/// output. This mostly affects multi-crate tests (those with path
/// dependencies). Removing the directory first guarantees a clean build
/// regardless of any leftover state, at no meaningful cost: a test is only
/// re-run when its inputs changed, in which case cargo would rebuild these
/// crates anyway.
///
/// A missing directory is fine (e.g. on the first run), but any other
/// removal failure (permissions, a held lock, ...) would leave the stale
/// state in place and reintroduce the non-determinism this guards against,
/// so we fail the test loudly instead of ignoring it.
fn clean_cargo_target_dir(&self) -> PathBuf {
let target_dir = self.output_base_dir().join("target");
match fs::remove_dir_all(&target_dir) {
Ok(()) => {}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
Err(error) => fatal_error(&format!(
"failed to remove stale target directory `{}`: {error}",
target_dir.display()
)),
}
target_dir
}

/// Runs cargo-kani on the function specified by the stem of `self.testpaths.file`.
/// The `test` parameter controls whether to specify `--tests` to `cargo kani`.
/// An error message is printed to stdout if verification output does not
Expand All @@ -269,11 +304,9 @@ impl TestCx<'_> {
let parent_dir = self.testpaths.file.parent().unwrap();
// The name of the function to test is the same as the stem of `*.expected` file
let function_name = self.testpaths.file.file_stem().unwrap().to_str().unwrap();
cargo
.arg("kani")
.arg("--target-dir")
.arg(self.output_base_dir().join("target"))
.current_dir(parent_dir);
// Start each run from a clean target directory (see `clean_cargo_target_dir`).
let target_dir = self.clean_cargo_target_dir();
cargo.arg("kani").arg("--target-dir").arg(&target_dir).current_dir(parent_dir);
if test {
cargo.arg("--tests");
}
Expand Down Expand Up @@ -338,12 +371,14 @@ impl TestCx<'_> {
let parent_dir = self.testpaths.file.parent().unwrap();
// The name of the function to test is the same as the stem of `*.expected` file
let function_name = self.testpaths.file.file_stem().unwrap().to_str().unwrap();
// Start each run from a clean target directory (see `clean_cargo_target_dir`).
let target_dir = self.clean_cargo_target_dir();
cargo
.arg("kani")
.arg("--coverage")
.arg("-Zsource-coverage")
.arg("--target-dir")
.arg(self.output_base_dir().join("target"))
.arg(&target_dir)
.current_dir(parent_dir);

if "expected" != self.testpaths.file.file_name().unwrap() {
Expand Down
Loading