Skip to content

Commit 5d0ccca

Browse files
authored
Autoharness: metadata improvements and enable standard library application (#3948)
Update the autoharness subcommand to: - Print the types of the arguments that don't implement Arbitrary - Print a table of the functions we chose to verify after codegen finishes, and move the printing of the functions we skipped to be after codegen as well, instead of after verification. This lets us iterate faster to debug because we can pass `--only-codegen` and see pretty-printed data instead of waiting for verification to finish. - Add a `--std` flag which, when provided, runs autoharness against the provided path to the standard library. 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 62dd13c commit 5d0ccca

File tree

17 files changed

+353
-181
lines changed

17 files changed

+353
-181
lines changed

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +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,
616+
autoharness_md: None,
617617
}
618618
}
619619

kani-compiler/src/kani_middle/codegen_units.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::kani_middle::resolve::expect_resolve_fn;
1818
use crate::kani_middle::stubbing::{check_compatibility, harness_stub_map};
1919
use crate::kani_queries::QueryDb;
2020
use kani_metadata::{
21-
ArtifactType, AssignsContract, AutoHarnessSkipReason, AutoHarnessSkippedFns, HarnessKind,
21+
ArtifactType, AssignsContract, AutoHarnessMetadata, AutoHarnessSkipReason, HarnessKind,
2222
HarnessMetadata, KaniMetadata,
2323
};
2424
use rustc_hir::def_id::DefId;
@@ -32,6 +32,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
3232
use std::fs::File;
3333
use std::io::BufWriter;
3434
use std::path::{Path, PathBuf};
35+
use std::sync::OnceLock;
3536
use tracing::debug;
3637

3738
/// An identifier for the harness function.
@@ -40,6 +41,8 @@ type Harness = Instance;
4041
/// A set of stubs.
4142
pub type Stubs = HashMap<FnDef, FnDef>;
4243

44+
static AUTOHARNESS_MD: OnceLock<AutoHarnessMetadata> = OnceLock::new();
45+
4346
/// Store some relevant information about the crate compilation.
4447
#[derive(Clone, Debug)]
4548
struct CrateInfo {
@@ -49,7 +52,6 @@ struct CrateInfo {
4952

5053
/// We group the harnesses that have the same stubs.
5154
pub struct CodegenUnits {
52-
autoharness_skipped_fns: Option<AutoHarnessSkippedFns>,
5355
crate_info: CrateInfo,
5456
harness_info: HashMap<Harness, HarnessMetadata>,
5557
units: Vec<CodegenUnit>,
@@ -74,12 +76,7 @@ impl CodegenUnits {
7476
let units = group_by_stubs(tcx, &all_harnesses);
7577
validate_units(tcx, &units);
7678
debug!(?units, "CodegenUnits::new");
77-
CodegenUnits {
78-
units,
79-
harness_info: all_harnesses,
80-
crate_info,
81-
autoharness_skipped_fns: None,
82-
}
79+
CodegenUnits { units, harness_info: all_harnesses, crate_info }
8380
}
8481
ReachabilityType::AllFns => {
8582
let mut all_harnesses = get_all_manual_harnesses(tcx, base_filename);
@@ -95,6 +92,11 @@ impl CodegenUnits {
9592
args,
9693
*kani_fns.get(&KaniModel::Any.into()).unwrap(),
9794
);
95+
let chosen_fn_names =
96+
chosen.iter().map(|func| func.name().clone()).collect::<Vec<_>>();
97+
AUTOHARNESS_MD
98+
.set(AutoHarnessMetadata { chosen: chosen_fn_names, skipped })
99+
.expect("Initializing the autoharness metdata failed");
98100

99101
let automatic_harnesses = get_all_automatic_harnesses(
100102
tcx,
@@ -117,21 +119,11 @@ impl CodegenUnits {
117119

118120
// No need to validate the units again because validation only checks stubs, and we haven't added any stubs.
119121
debug!(?units, "CodegenUnits::new");
120-
CodegenUnits {
121-
units,
122-
harness_info: all_harnesses,
123-
crate_info,
124-
autoharness_skipped_fns: Some(skipped),
125-
}
122+
CodegenUnits { units, harness_info: all_harnesses, crate_info }
126123
}
127124
_ => {
128125
// Leave other reachability type handling as is for now.
129-
CodegenUnits {
130-
units: vec![],
131-
harness_info: HashMap::default(),
132-
crate_info,
133-
autoharness_skipped_fns: None,
134-
}
126+
CodegenUnits { units: vec![], harness_info: HashMap::default(), crate_info }
135127
}
136128
}
137129
}
@@ -176,7 +168,7 @@ impl CodegenUnits {
176168
unsupported_features: vec![],
177169
test_harnesses,
178170
contracted_functions: gen_contracts_metadata(tcx),
179-
autoharness_skipped_fns: self.autoharness_skipped_fns.clone(),
171+
autoharness_md: AUTOHARNESS_MD.get().cloned(),
180172
}
181173
}
182174
}
@@ -432,7 +424,8 @@ fn automatic_harness_partition(
432424
var.argument_index.is_some_and(|arg_idx| idx + 1 == usize::from(arg_idx))
433425
})
434426
.map_or("_".to_string(), |debug_info| debug_info.name.to_string());
435-
problematic_args.push(arg_name)
427+
let arg_type = format!("{}", arg.ty);
428+
problematic_args.push((arg_name, arg_type))
436429
}
437430
}
438431
if !problematic_args.is_empty() {

kani-driver/src/args/autoharness_args.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use std::path::PathBuf;
66

7-
use crate::args::{ValidateArgs, VerificationArgs};
7+
use crate::args::{ValidateArgs, VerificationArgs, validate_std_path};
88
use clap::{Error, Parser, error::ErrorKind};
99
use kani_metadata::UnstableFeature;
1010

@@ -54,6 +54,11 @@ pub struct StandaloneAutoharnessArgs {
5454
#[command(flatten)]
5555
pub common_autoharness_args: CommonAutoharnessArgs,
5656

57+
/// Pass this flag to run the `autoharness` subcommand on the standard library.
58+
/// Ensure that the provided `input` is the `library` folder.
59+
#[arg(long)]
60+
pub std: bool,
61+
5762
#[command(flatten)]
5863
pub verify_opts: VerificationArgs,
5964
}
@@ -99,7 +104,10 @@ impl ValidateArgs for StandaloneAutoharnessArgs {
99104
),
100105
));
101106
}
102-
if !self.input.is_file() {
107+
108+
if self.std {
109+
validate_std_path(&self.input)?;
110+
} else if !self.input.is_file() {
103111
return Err(Error::raw(
104112
ErrorKind::InvalidValue,
105113
format!(

kani-driver/src/args/list_args.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use std::path::PathBuf;
66

7-
use crate::args::{CommonArgs, ValidateArgs};
7+
use crate::args::{CommonArgs, ValidateArgs, validate_std_path};
88
use clap::{Error, Parser, ValueEnum, error::ErrorKind};
99
use kani_metadata::UnstableFeature;
1010

@@ -79,39 +79,7 @@ impl ValidateArgs for StandaloneListArgs {
7979
}
8080

8181
if self.std {
82-
if !self.input.exists() {
83-
Err(Error::raw(
84-
ErrorKind::InvalidValue,
85-
format!(
86-
"Invalid argument: `<input>` argument `{}` does not exist",
87-
self.input.display()
88-
),
89-
))
90-
} else if !self.input.is_dir() {
91-
Err(Error::raw(
92-
ErrorKind::InvalidValue,
93-
format!(
94-
"Invalid argument: `<input>` argument `{}` is not a directory",
95-
self.input.display()
96-
),
97-
))
98-
} else {
99-
let full_path = self.input.canonicalize()?;
100-
let dir = full_path.file_stem().unwrap();
101-
if dir != "library" {
102-
Err(Error::raw(
103-
ErrorKind::InvalidValue,
104-
format!(
105-
"Invalid argument: Expected `<input>` to point to the `library` folder \
106-
containing the standard library crates.\n\
107-
Found `{}` folder instead",
108-
dir.to_string_lossy()
109-
),
110-
))
111-
} else {
112-
Ok(())
113-
}
114-
}
82+
validate_std_path(&self.input)
11583
} else if self.input.is_file() {
11684
Ok(())
11785
} else {

kani-driver/src/args/mod.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use clap::builder::{PossibleValue, TypedValueParser};
2020
use clap::{ValueEnum, error::ContextKind, error::ContextValue, error::Error, error::ErrorKind};
2121
use kani_metadata::CbmcSolver;
2222
use std::ffi::OsString;
23-
use std::path::PathBuf;
23+
use std::path::{Path, PathBuf};
2424
use std::str::FromStr;
2525
use std::time::Duration;
2626
use strum::VariantNames;
@@ -789,6 +789,42 @@ impl ValidateArgs for VerificationArgs {
789789
}
790790
}
791791

792+
pub(crate) fn validate_std_path(std_path: &Path) -> Result<(), Error> {
793+
if !std_path.exists() {
794+
Err(Error::raw(
795+
ErrorKind::InvalidValue,
796+
format!(
797+
"Invalid argument: `<STD_PATH>` argument `{}` does not exist",
798+
std_path.display()
799+
),
800+
))
801+
} else if !std_path.is_dir() {
802+
Err(Error::raw(
803+
ErrorKind::InvalidValue,
804+
format!(
805+
"Invalid argument: `<STD_PATH>` argument `{}` is not a directory",
806+
std_path.display()
807+
),
808+
))
809+
} else {
810+
let full_path = std_path.canonicalize()?;
811+
let dir = full_path.file_stem().unwrap();
812+
if dir != "library" {
813+
Err(Error::raw(
814+
ErrorKind::InvalidValue,
815+
format!(
816+
"Invalid argument: Expected `<STD_PATH>` to point to the `library` folder \
817+
containing the standard library crates.\n\
818+
Found `{}` folder instead",
819+
dir.to_string_lossy()
820+
),
821+
))
822+
} else {
823+
Ok(())
824+
}
825+
}
826+
}
827+
792828
/// clap parser for `CbmcSolver`
793829
#[derive(Clone, Debug)]
794830
pub struct CbmcSolverValueParser(Vec<PossibleValue>);

kani-driver/src/args/std_args.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
//! Implements the `verify-std` subcommand handling.
55
6-
use crate::args::{ValidateArgs, VerificationArgs};
6+
use crate::args::{ValidateArgs, VerificationArgs, validate_std_path};
77
use clap::error::ErrorKind;
88
use clap::{Error, Parser};
99
use kani_metadata::UnstableFeature;
@@ -40,38 +40,6 @@ impl ValidateArgs for VerifyStdArgs {
4040
));
4141
}
4242

43-
if !self.std_path.exists() {
44-
Err(Error::raw(
45-
ErrorKind::InvalidValue,
46-
format!(
47-
"Invalid argument: `<STD_PATH>` argument `{}` does not exist",
48-
self.std_path.display()
49-
),
50-
))
51-
} else if !self.std_path.is_dir() {
52-
Err(Error::raw(
53-
ErrorKind::InvalidValue,
54-
format!(
55-
"Invalid argument: `<STD_PATH>` argument `{}` is not a directory",
56-
self.std_path.display()
57-
),
58-
))
59-
} else {
60-
let full_path = self.std_path.canonicalize()?;
61-
let dir = full_path.file_stem().unwrap();
62-
if dir != "library" {
63-
Err(Error::raw(
64-
ErrorKind::InvalidValue,
65-
format!(
66-
"Invalid argument: Expected `<STD_PATH>` to point to the `library` folder \
67-
containing the standard library crates.\n\
68-
Found `{}` folder instead",
69-
dir.to_string_lossy()
70-
),
71-
))
72-
} else {
73-
Ok(())
74-
}
75-
}
43+
validate_std_path(&self.std_path)
7644
}
7745
}

0 commit comments

Comments
 (0)