Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to CBMC version 6.1.1 #2995

Merged
merged 62 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
da76cb3
Update to CBMC version 6.0.0
tautschnig Feb 6, 2024
2f37c6f
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jun 18, 2024
d6e78a8
Force tests to pass
tautschnig Jun 19, 2024
1bc0129
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jun 19, 2024
5d73a67
Add overlay files to enable performance data output
tautschnig Jun 19, 2024
e95e689
Enable verbosity 9 for performance numbers
tautschnig Jun 19, 2024
7feccd5
Revert "Enable verbosity 9 for performance numbers"
tautschnig Jun 19, 2024
0125a23
Revert "Add overlay files to enable performance data output"
tautschnig Jun 19, 2024
9a68859
Verbosity 9 for perf tests
tautschnig Jun 19, 2024
7dd43d8
Separate flags
tautschnig Jun 19, 2024
a55167a
benchcomp test with verbosity
tautschnig Jun 19, 2024
952841d
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jun 20, 2024
e32e3c6
Revert "Force tests to pass"
tautschnig Jun 20, 2024
383a6f4
Set higher verbosity for tests as needed
tautschnig Jun 20, 2024
11b1dd1
Update interface to CBMC v6
tautschnig Jun 20, 2024
d591c4d
Regression test workarounds
tautschnig Jun 20, 2024
3abf589
Revert "Regression test workarounds"
tautschnig Jun 20, 2024
d07841b
Debugging storage markers
tautschnig Apr 25, 2024
c179663
WIP
tautschnig Apr 25, 2024
2db2a0d
Codegen storage markers as assignments to __CPROVER_dead_object
tautschnig Apr 26, 2024
bb5dc8f
Revert #3080 except for std enablement
tautschnig Apr 26, 2024
e29d024
Mark failure that is not yet understood as FIXME
tautschnig Jun 20, 2024
6480755
Mark newly slow tests as such
tautschnig Jun 20, 2024
445f363
Update property configuration for CBMC v6
tautschnig Jun 20, 2024
bb373f2
fixup! Set higher verbosity for tests as needed
tautschnig Jun 20, 2024
fda6424
Use CBMC version 6.0.1
tautschnig Jun 21, 2024
125473d
Use PPA with GCC-9 to build CBMC v6+ on Ubuntu 18.04
tautschnig Jun 21, 2024
e7242f2
Use older pip version to remain compatible with Python 3.7
tautschnig Jun 21, 2024
7f996e7
Factor out access to __CPROVER_dead_object
tautschnig Jun 21, 2024
93398cb
Revert "Mark failure that is not yet understood as FIXME"
tautschnig Jun 21, 2024
dcc9d61
fixup! Codegen storage markers as assignments to __CPROVER_dead_object
tautschnig Jun 21, 2024
2001ae8
Remove TODO as CBMC will not necessarily pick this up
tautschnig Jun 21, 2024
59d2fba
Fix Docker as well
tautschnig Jun 21, 2024
42ed007
fixup! fixup! Codegen storage markers as assignments to __CPROVER_dea…
tautschnig Jun 21, 2024
268a0c0
Add comment
tautschnig Jun 24, 2024
ebe6cdb
Build static binaries on Linux 18.04
tautschnig Jun 24, 2024
2545e0c
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jun 24, 2024
62d9f85
Comment explaining StorageLive/StorageDead modelling
tautschnig Jun 24, 2024
d273960
Extend comment
tautschnig Jun 24, 2024
728c1f7
Merge branch 'main' into cbmc-6
tautschnig Jun 25, 2024
df95895
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jul 23, 2024
9d2e3e5
Use CBMC 6.1.0
tautschnig Jul 23, 2024
b7b3b15
Test performance with CBMC using CaDiCaL 2.0.0
tautschnig Jul 23, 2024
fd78563
Merge branch 'main' into cbmc-6
tautschnig Jul 23, 2024
bdb80ea
Merge branch 'main' into cbmc-6
tautschnig Jul 24, 2024
033b27d
Work around CaDiCaL performance regression
tautschnig Jul 24, 2024
8cd357a
Revert "Work around CaDiCaL performance regression"
tautschnig Jul 24, 2024
277bdad
Bump s2n-quic submodule
tautschnig Jul 24, 2024
f938676
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jul 24, 2024
c1bc1ee
Benchcomp perf regression: move setup into run
tautschnig Jul 24, 2024
f60db0e
Revert "Benchcomp perf regression: move setup into run"
tautschnig Jul 24, 2024
85092ed
Install variant-specific dependencies
tautschnig Jul 24, 2024
d94175c
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jul 25, 2024
8127e5c
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jul 25, 2024
8bb15ce
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jul 26, 2024
7ab6f60
Use Local
tautschnig Jul 26, 2024
e902354
Use constant
tautschnig Jul 26, 2024
007b1e9
Merge branch 'main' into cbmc-6
tautschnig Jul 30, 2024
2a3fd06
Merge remote-tracking branch 'origin/main' into cbmc-6
tautschnig Jul 31, 2024
c968d65
Use CBMC 6.1.1
tautschnig Jul 31, 2024
2de6464
Revert "Test performance with CBMC using CaDiCaL 2.0.0"
tautschnig Jul 31, 2024
f878fd9
Use verbosity 9 by default
tautschnig Jul 31, 2024
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
15 changes: 14 additions & 1 deletion cprover_bindings/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! c.f. CBMC code [src/ansi-c/ansi_c_internal_additions.cpp].
//! One possible invocation of this insertion in CBMC can be found in \[ansi_c_languaget::parse\].

use super::goto_program::{Expr, Location, Symbol, Type};
use super::goto_program::{Expr, Location, Symbol, SymbolTable, Type};
use super::MachineModel;
use num::bigint::BigInt;
fn int_constant<T>(name: &str, value: T) -> Symbol
Expand Down Expand Up @@ -71,6 +71,8 @@ pub fn machine_model_symbols(mm: &MachineModel) -> Vec<Symbol> {
]
}

const DEAD_OBJECT_IDENTIFIER: &str = "__CPROVER_dead_object";

pub fn additional_env_symbols() -> Vec<Symbol> {
vec![
Symbol::builtin_function("__CPROVER_initialize", vec![], Type::empty()),
Expand All @@ -82,5 +84,16 @@ pub fn additional_env_symbols() -> Vec<Symbol> {
Location::none(),
)
.with_is_extern(true),
Symbol::static_variable(
DEAD_OBJECT_IDENTIFIER,
DEAD_OBJECT_IDENTIFIER,
Type::void_pointer(),
Location::none(),
)
.with_is_extern(true),
]
}

pub fn global_dead_object(symbol_table: &SymbolTable) -> Expr {
symbol_table.lookup(DEAD_OBJECT_IDENTIFIER).unwrap().to_expr()
}
10 changes: 5 additions & 5 deletions cprover_bindings/src/irep/goto_binary_serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::io::{self, BufReader};
use std::io::{BufWriter, Bytes, Error, ErrorKind, Read, Write};
use std::path::Path;

/// Writes a symbol table to a file in goto binary format in version 5.
/// Writes a symbol table to a file in goto binary format in version 6.
///
/// In CBMC, the serialization rules are defined in :
/// - src/goto-programs/write_goto_binary.h
Expand All @@ -26,7 +26,7 @@ pub fn write_goto_binary_file(filename: &Path, source: &crate::goto_program::Sym
serializer.write_file(irep_symbol_table);
}

/// Reads a symbol table from a file expected to be in goto binary format in version 5.
/// Reads a symbol table from a file expected to be in goto binary format in version 6.
//
/// In CBMC, the deserialization rules are defined in :
/// - src/goto-programs/read_goto_binary.h
Expand Down Expand Up @@ -540,7 +540,7 @@ where
assert!(written == 4);

// Write goto binary version
self.write_usize_varenc(5);
self.write_usize_varenc(6);
}

/// Writes the symbol table using the GOTO binary file format to the byte stream.
Expand Down Expand Up @@ -921,12 +921,12 @@ where

// Read goto binary version
let goto_binary_version = self.read_usize_varenc()?;
if goto_binary_version != 5 {
if goto_binary_version != 6 {
return Err(Error::new(
ErrorKind::Other,
format!(
"Unsupported GOTO binary version: {}. Supported version: {}",
goto_binary_version, 5
goto_binary_version, 6
),
));
}
Expand Down
4 changes: 2 additions & 2 deletions cprover_bindings/src/irep/irep_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ pub enum IrepId {
Div,
Power,
FactorialPower,
PrettyName,
CPrettyName,
CClass,
CField,
CInterface,
Expand Down Expand Up @@ -1242,7 +1242,7 @@ impl Display for IrepId {
IrepId::Div => "/",
IrepId::Power => "**",
IrepId::FactorialPower => "factorial_power",
IrepId::PrettyName => "pretty_name",
IrepId::CPrettyName => "#pretty_name",
IrepId::CClass => "#class",
IrepId::CField => "#field",
IrepId::CInterface => "#interface",
Expand Down
2 changes: 1 addition & 1 deletion cprover_bindings/src/irep/to_irep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl ToIrep for DatatypeComponent {
match self {
DatatypeComponent::Field { name, typ } => Irep::just_named_sub(linear_map![
(IrepId::Name, Irep::just_string_id(name.to_string())),
(IrepId::PrettyName, Irep::just_string_id(name.to_string())),
(IrepId::CPrettyName, Irep::just_string_id(name.to_string())),
(IrepId::Type, typ.to_irep(mm)),
]),
DatatypeComponent::Padding { name, bits } => Irep::just_named_sub(linear_map![
Expand Down
1 change: 1 addition & 0 deletions cprover_bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#![feature(f16)]

mod env;
pub use env::global_dead_object;
pub mod goto_program;
pub mod irep;
mod machine_model;
Expand Down
3 changes: 0 additions & 3 deletions kani-compiler/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ pub struct Arguments {
/// Enable specific checks.
#[clap(long)]
pub ub_check: Vec<ExtraChecks>,
/// Ignore storage markers.
#[clap(long)]
pub ignore_storage_markers: bool,
}

#[derive(Debug, Clone, Copy, AsRefStr, EnumString, VariantNames, PartialEq, Eq)]
Expand Down
59 changes: 55 additions & 4 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,68 @@ impl<'tcx> GotocCtx<'tcx> {
.goto_expr;
self.codegen_set_discriminant(dest_ty, dest_expr, *variant_index, location)
}
// StorageLive and StorageDead are modelled via CBMC's internal means of detecting
// accesses to dangling pointers, which uses demonic non-determinism. That is, CBMC
// non-deterministically chooses a single object's address to be tracked in a
// pointer-typed global instrumentation variable __CPROVER_dead_object. Any dereference
// entails a check that the pointer being dereferenced is not equal to the pointer held
// in __CPROVER_dead_object. We use this to bridge the difference between Rust and MIR
// semantics as follows:
//
// 1. (At the time of writing) MIR declares all function-local variables at function
// scope, irrespective of the scope/block that Rust code originally used.
// 2. In MIR, StorageLive and StorageDead markers are inserted at the beginning and end
// of the Rust block to record the Rust-level lifetime of the object.
// 3. We translate MIR declarations into GOTO declarations, implying that we will have
// a single object per function for a local variable, even when Rust had a variable
// declared in a sub-scope of the function where said scope was entered multiple
// times (e.g., a loop body).
// 4. To enable detection of use of dangling pointers, we now use
// __CPROVER_dead_object, unless the address of the local object is never taken
// (implying that there cannot be a use of a dangling pointer with respect to said
// object). We update __CPROVER_dead_object as follows:
// * StorageLive is set to NULL when __CPROVER_dead_object pointed to the object
// (re-)entering scope, or else is left unchanged.
// * StorageDead non-deterministically updates (or leaves unchanged)
// __CPROVER_dead_object to point to the object going out of scope. (This is the
// same update approach as used within CBMC.)
//
// This approach will also work when there are multiple occurrences of StorageLive (or
// StorageDead) on a path, or across control-flow branches, and even when StorageDead
// occurs without a preceding StorageLive.
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
StatementKind::StorageLive(var_id) => {
if self.queries.args().ignore_storage_markers {
if !self.current_fn().is_address_taken_local(*var_id) {
Stmt::skip(location)
} else {
Stmt::decl(self.codegen_local(*var_id, location), None, location)
let global_dead_object = cbmc::global_dead_object(&self.symbol_table);
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
Stmt::assign(
global_dead_object.clone(),
global_dead_object
.clone()
.eq(self
.codegen_local(*var_id, location)
.address_of()
.cast_to(global_dead_object.typ().clone()))
.ternary(global_dead_object.typ().null(), global_dead_object),
location,
)
}
}
StatementKind::StorageDead(var_id) => {
if self.queries.args().ignore_storage_markers {
if !self.current_fn().is_address_taken_local(*var_id) {
Stmt::skip(location)
} else {
Stmt::dead(self.codegen_local(*var_id, location), location)
let global_dead_object = cbmc::global_dead_object(&self.symbol_table);
Stmt::assign(
global_dead_object.clone(),
Type::bool().nondet().ternary(
self.codegen_local(*var_id, location)
.address_of()
.cast_to(global_dead_object.typ().clone()),
global_dead_object,
),
location,
)
}
}
StatementKind::Intrinsic(NonDivergingIntrinsic::CopyNonOverlapping(
Expand Down Expand Up @@ -424,6 +474,7 @@ impl<'tcx> GotocCtx<'tcx> {
.branches()
.map(|(c, bb)| {
Expr::int_constant(c, switch_ty.clone())
.with_location(loc)
.switch_case(Stmt::goto(bb_label(bb), loc))
})
.collect();
Expand Down
31 changes: 29 additions & 2 deletions kani-compiler/src/codegen_cprover_gotoc/context/current_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use cbmc::InternedString;
use rustc_middle::ty::Instance as InstanceInternal;
use rustc_smir::rustc_internal;
use stable_mir::mir::mono::Instance;
use stable_mir::mir::{Body, Local, LocalDecl};
use stable_mir::mir::{visit::Location, visit::MirVisitor, Body, Local, LocalDecl, Rvalue};
use stable_mir::CrateDef;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

/// This structure represents useful data about the function we are currently compiling.
#[derive(Debug)]
Expand All @@ -26,6 +26,8 @@ pub struct CurrentFnCtx<'tcx> {
locals: Vec<LocalDecl>,
/// A list of pretty names for locals that corrspond to user variables.
local_names: HashMap<Local, InternedString>,
/// Collection of variables that are used in a reference or address-of expression.
address_taken_locals: HashSet<Local>,
/// The symbol name of the current function
name: String,
/// A human readable pretty name for the current function
Expand All @@ -34,6 +36,24 @@ pub struct CurrentFnCtx<'tcx> {
temp_var_counter: u64,
}

struct AddressTakenLocalsCollector {
/// Locals that appear in `Rvalue::Ref` or `Rvalue::AddressOf` expressions.
address_taken_locals: HashSet<Local>,
}

impl MirVisitor for AddressTakenLocalsCollector {
fn visit_rvalue(&mut self, rvalue: &Rvalue, _location: Location) {
match rvalue {
Rvalue::Ref(_, _, p) | Rvalue::AddressOf(_, p) => {
if p.projection.is_empty() {
self.address_taken_locals.insert(p.local);
}
}
_ => (),
}
}
}

/// Constructor
impl<'tcx> CurrentFnCtx<'tcx> {
pub fn new(instance: Instance, gcx: &GotocCtx<'tcx>, body: &Body) -> Self {
Expand All @@ -46,13 +66,16 @@ impl<'tcx> CurrentFnCtx<'tcx> {
.iter()
.filter_map(|info| info.local().map(|local| (local, (&info.name).into())))
.collect::<HashMap<_, _>>();
let mut visitor = AddressTakenLocalsCollector { address_taken_locals: HashSet::new() };
visitor.visit_body(body);
Self {
block: vec![],
instance,
instance_internal,
krate: instance.def.krate().name,
locals,
local_names,
address_taken_locals: visitor.address_taken_locals,
name,
readable_name,
temp_var_counter: 0,
Expand Down Expand Up @@ -106,6 +129,10 @@ impl<'tcx> CurrentFnCtx<'tcx> {
pub fn local_name(&self, local: Local) -> Option<InternedString> {
self.local_names.get(&local).copied()
}

pub fn is_address_taken_local(&self, local: Local) -> bool {
self.address_taken_locals.contains(&local)
}
}

/// Utility functions
Expand Down
6 changes: 3 additions & 3 deletions kani-dependencies
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CBMC_MAJOR="5"
CBMC_MINOR="95"
CBMC_VERSION="5.95.1"
CBMC_MAJOR="6"
CBMC_MINOR="1"
CBMC_VERSION="6.1.1"

# If you update this version number, remember to bump it in `src/setup.rs` too
CBMC_VIEWER_MAJOR="3"
Expand Down
8 changes: 0 additions & 8 deletions kani-driver/src/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,6 @@ pub struct VerificationArgs {
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
pub ignore_global_asm: bool,

/// Ignore lifetimes of local variables. This effectively extends their
/// lifetimes to the function scope, and hence may cause Kani to miss
/// undefined behavior resulting from using the variable after it dies.
/// This option may impact the soundness of the analysis and may cause false
/// proofs and/or counterexamples
#[arg(long, hide_short_help = true, requires("enable_unstable"))]
pub ignore_locals_lifetime: bool,

/// Write the GotoC symbol table to a file in JSON format instead of goto binary format.
#[arg(long, hide_short_help = true)]
pub write_json_symtab: bool,
Expand Down
39 changes: 27 additions & 12 deletions kani-driver/src/call_cbmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,37 +153,51 @@ impl KaniSession {

args.push(file.to_owned().into_os_string());

// Make CBMC verbose by default to tell users about unwinding progress. This should be
// reviewed as CBMC's verbosity defaults evolve.
args.push("--verbosity".into());
args.push("9".into());

Ok(args)
}

/// Just the flags to CBMC that enable property checking of any sort.
pub fn cbmc_check_flags(&self) -> Vec<OsString> {
let mut args = Vec::new();

if self.args.checks.memory_safety_on() {
args.push("--bounds-check".into());
args.push("--pointer-check".into());
// We assume that malloc cannot fail, see https://github.com/model-checking/kani/issues/891
args.push("--no-malloc-may-fail".into());
tautschnig marked this conversation as resolved.
Show resolved Hide resolved

// With PR #2630 we generate the appropriate checks directly rather than relying on CBMC's
// checks (which are for C semantics).
args.push("--no-undefined-shift-check".into());
// With PR #647 we use Rust's `-C overflow-checks=on` instead of:
// --unsigned-overflow-check
// --signed-overflow-check
// So these options are deliberately skipped to avoid erroneously re-checking operations.
args.push("--no-signed-overflow-check".into());

if !self.args.checks.memory_safety_on() {
args.push("--no-bounds-check".into());
args.push("--no-pointer-check".into());
}
if self.args.checks.overflow_on() {
args.push("--div-by-zero-check".into());
args.push("--float-overflow-check".into());
args.push("--nan-check".into());
// With PR #647 we use Rust's `-C overflow-checks=on` instead of:
// --unsigned-overflow-check
// --signed-overflow-check
// So these options are deliberately skipped to avoid erroneously re-checking operations.

// TODO: Implement conversion checks as an optional check.
// They are a well defined operation in rust, but they may yield unexpected results to
// many users. https://github.com/model-checking/kani/issues/840
// We might want to create a transformation pass instead of enabling CBMC since Kani
// compiler sometimes rely on the bitwise conversion of signed <-> unsigned.
// args.push("--conversion-check".into());
} else {
args.push("--no-div-by-zero-check".into());
}

if self.args.checks.unwinding_on() {
// TODO: With CBMC v6 the below can be removed as those are defaults.
args.push("--unwinding-assertions".into());
if !self.args.checks.unwinding_on() {
args.push("--no-unwinding-assertions".into());
} else {
args.push("--no-self-loops-to-assumptions".into());
}

Expand All @@ -192,7 +206,8 @@ impl KaniSession {
// still catch any invalid dereference with --pointer-check. Thus, only enable them
// if the user explicitly request them.
args.push("--pointer-overflow-check".into());
args.push("--pointer-primitive-check".into());
} else {
args.push("--no-pointer-primitive-check".into());
}

args
Expand Down
2 changes: 2 additions & 0 deletions kani-driver/src/call_goto_instrument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ impl KaniSession {
fn add_library(&self, file: &Path) -> Result<()> {
let args: Vec<OsString> = vec![
"--add-library".into(),
"--no-malloc-may-fail".into(),
file.to_owned().into_os_string(), // input
file.to_owned().into_os_string(), // output
];
Expand Down Expand Up @@ -173,6 +174,7 @@ impl KaniSession {
assigns.contracted_function_name.as_str().into(),
"--nondet-static-exclude".into(),
assigns.recursion_tracker.as_str().into(),
"--no-malloc-may-fail".into(),
file.into(),
file.into(),
];
Expand Down
Loading
Loading