Skip to content

Commit 2a09d79

Browse files
authored
Perform reachability analysis on a per-harness basis (rust-lang#2439)
Kani compiler used to generate one `goto-program` for all harnesses in one crate. In some cases, this actually had a negative impact on the harness verification time. This was first reported in rust-lang#1659 The main changes were done in the compiler's module `compiler_interface` and the module `project` from the driver. The compiler will now gather all the harnesses beforehand and it will perform reachability + codegen steps for each harness. All files related to a harness `goto-program` will follow the naming convention bellow: ``` <BASE_NAME>_<MANGLED_NAME>.<EXTENSION> ``` This applies to symtab / goto / type_map / restriction files. The metadata file is still generated once per target crate, and its name is still the same (`<BASE_NAME>.kani-metadata.json`). On the driver side, the way we process the artifacts have changed. The driver will now read the metadata for each crate, and collect all artifacts based on the symtab goto file that is recorded in the metadata of each harness. These changes do not apply for `--function`. We still keep all artifacts based on the crate's `<BASE_NAME>` and we have a separate logic to handle that. Fixing this is captured by rust-lang#2129.
1 parent 38e5913 commit 2a09d79

File tree

19 files changed

+701
-509
lines changed

19 files changed

+701
-509
lines changed

cprover_bindings/src/irep/goto_binary_serde.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::fs::File;
99
use std::hash::Hash;
1010
use std::io::{self, BufReader};
1111
use std::io::{BufWriter, Bytes, Error, ErrorKind, Read, Write};
12-
use std::path::PathBuf;
12+
use std::path::Path;
1313

1414
/// Writes a symbol table to a file in goto binary format in version 5.
1515
///
@@ -18,7 +18,7 @@ use std::path::PathBuf;
1818
/// - src/util/irep_serialization.h
1919
/// - src/util/irep_hash_container.h
2020
/// - src/util/irep_hash.h
21-
pub fn write_goto_binary_file(filename: &PathBuf, source: &crate::goto_program::SymbolTable) {
21+
pub fn write_goto_binary_file(filename: &Path, source: &crate::goto_program::SymbolTable) {
2222
let out_file = File::create(filename).unwrap();
2323
let mut writer = BufWriter::new(out_file);
2424
let mut serializer = GotoBinarySerializer::new(&mut writer);
@@ -33,7 +33,7 @@ pub fn write_goto_binary_file(filename: &PathBuf, source: &crate::goto_program::
3333
/// - src/util/irep_serialization.h
3434
/// - src/util/irep_hash_container.h
3535
/// - src/util/irep_hash.h
36-
pub fn read_goto_binary_file(filename: &PathBuf) -> io::Result<()> {
36+
pub fn read_goto_binary_file(filename: &Path) -> io::Result<()> {
3737
let file = File::open(filename)?;
3838
let reader = BufReader::new(file);
3939
let mut deserializer = GotoBinaryDeserializer::new(reader);

kani-compiler/src/codegen_cprover_gotoc/codegen/function.rs

-51
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
//! This file contains functions related to codegenning MIR functions into gotoc
55
66
use crate::codegen_cprover_gotoc::GotocCtx;
7-
use crate::kani_middle::attributes::{extract_harness_attributes, is_test_harness_closure};
87
use cbmc::goto_program::{Expr, Stmt, Symbol};
98
use cbmc::InternString;
10-
use kani_metadata::{HarnessAttributes, HarnessMetadata};
119
use rustc_middle::mir::traversal::reverse_postorder;
1210
use rustc_middle::mir::{Body, HasLocalDecls, Local};
1311
use rustc_middle::ty::{self, Instance};
@@ -89,9 +87,6 @@ impl<'tcx> GotocCtx<'tcx> {
8987
let stmts = self.current_fn_mut().extract_block();
9088
let body = Stmt::block(stmts, loc);
9189
self.symbol_table.update_fn_declaration_with_definition(&name, body);
92-
93-
self.record_kani_attributes();
94-
self.record_test_harness_metadata();
9590
}
9691
self.reset_current_fn();
9792
}
@@ -244,50 +239,4 @@ impl<'tcx> GotocCtx<'tcx> {
244239
});
245240
self.reset_current_fn();
246241
}
247-
248-
/// We record test harness information in kani-metadata, just like we record
249-
/// proof harness information. This is used to support e.g. cargo-kani assess.
250-
///
251-
/// Note that we do not actually spot the function that was annotated by `#[test]`
252-
/// but instead the closure that gets put into the "test description" that macro
253-
/// expands into. (See comment below) This ends up being preferrable, actually,
254-
/// as it add asserts for tests that return `Result` types.
255-
fn record_test_harness_metadata(&mut self) {
256-
let def_id = self.current_fn().instance().def_id();
257-
if is_test_harness_closure(self.tcx, def_id) {
258-
self.test_harnesses.push(self.generate_metadata(None))
259-
}
260-
}
261-
262-
/// This updates the goto context with any information that should be accumulated from a function's
263-
/// attributes.
264-
///
265-
/// Handle all attributes i.e. `#[kani::x]` (which kani_macros translates to `#[kanitool::x]` for us to handle here)
266-
fn record_kani_attributes(&mut self) {
267-
let def_id = self.current_fn().instance().def_id();
268-
let attributes = extract_harness_attributes(self.tcx, def_id);
269-
if attributes.is_some() {
270-
self.proof_harnesses.push(self.generate_metadata(attributes));
271-
}
272-
}
273-
274-
/// Create the default proof harness for the current function
275-
fn generate_metadata(&self, attributes: Option<HarnessAttributes>) -> HarnessMetadata {
276-
let current_fn = self.current_fn();
277-
let pretty_name = current_fn.readable_name().to_owned();
278-
let mangled_name = current_fn.name();
279-
let loc = self.codegen_span(&current_fn.mir().span);
280-
281-
HarnessMetadata {
282-
pretty_name,
283-
mangled_name,
284-
crate_name: current_fn.krate(),
285-
original_file: loc.filename().unwrap(),
286-
original_start_line: loc.start_line().unwrap() as usize,
287-
original_end_line: loc.end_line().unwrap() as usize,
288-
attributes: attributes.unwrap_or_default(),
289-
// We record the actual path after codegen before we dump the metadata into a file.
290-
goto_file: None,
291-
}
292-
}
293242
}

kani-compiler/src/codegen_cprover_gotoc/codegen/span.rs

+7-18
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,21 @@
33

44
//! MIR Span related functions
55
6-
use crate::codegen_cprover_gotoc::GotocCtx;
6+
use crate::{codegen_cprover_gotoc::GotocCtx, kani_middle::SourceLocation};
77
use cbmc::goto_program::Location;
88
use rustc_middle::mir::{Local, VarDebugInfo, VarDebugInfoContents};
99
use rustc_span::Span;
1010

1111
impl<'tcx> GotocCtx<'tcx> {
1212
pub fn codegen_span(&self, sp: &Span) -> Location {
13-
let smap = self.tcx.sess.source_map();
14-
let lo = smap.lookup_char_pos(sp.lo());
15-
let start_line = lo.line;
16-
let start_col = 1 + lo.col_display;
17-
let hi = smap.lookup_char_pos(sp.hi());
18-
let end_line = hi.line;
19-
let end_col = 1 + hi.col_display;
20-
let filename0 = lo.file.name.prefer_local().to_string_lossy().to_string();
21-
let filename1 = match std::fs::canonicalize(filename0.clone()) {
22-
Ok(pathbuf) => pathbuf.to_str().unwrap().to_string(),
23-
Err(_) => filename0,
24-
};
13+
let loc = SourceLocation::new(self.tcx, sp);
2514
Location::new(
26-
filename1,
15+
loc.filename,
2716
self.current_fn.as_ref().map(|x| x.readable_name().to_string()),
28-
start_line,
29-
Some(start_col),
30-
end_line,
31-
Some(end_col),
17+
loc.start_line,
18+
Some(loc.start_col),
19+
loc.end_line,
20+
Some(loc.end_col),
3221
)
3322
}
3423

0 commit comments

Comments
 (0)