Skip to content

Commit 05b6252

Browse files
authored
Add unstable option prove-safety-only (#4239)
Compute verification results under the assumption that no panic occurs. This enables safety verification, i.e., proving the absence of undefined behavior without being distracted by panics which Kani, otherwise, also reports as verification failures. #4230 was an efforts towards the same goal, but required manual annotation of the conditions under which a panic may occur (and may hide undefined behavior when either the given specifications are too broad or when undefined behavior arises on a path to a panic). 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 1954c10 commit 05b6252

File tree

5 files changed

+53
-5
lines changed

5 files changed

+53
-5
lines changed

kani-compiler/src/args.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ pub struct Arguments {
6565
/// Option used for suppressing global ASM error.
6666
#[clap(long)]
6767
pub ignore_global_asm: bool,
68+
/// Compute verification results under the assumption that no panic occurs.
69+
/// This feature is unstable, and it requires `-Z unstable-options` to be used
70+
#[clap(long)]
71+
pub prove_safety_only: bool,
6872
/// Option name used to select which reachability analysis to perform.
6973
#[clap(long = "reachability", default_value = "none")]
7074
pub reachability_analysis: ReachabilityType,

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,18 @@ impl GotocCtx<'_> {
133133
message: &str,
134134
loc: Location,
135135
) -> Stmt {
136-
let property_name = property_class.as_str();
137-
Stmt::block(
138-
vec![Stmt::assert(cond.clone(), property_name, message, loc), Stmt::assume(cond, loc)],
139-
loc,
140-
)
136+
if property_class == PropertyClass::Assertion && self.queries.args().prove_safety_only {
137+
Stmt::assume(cond, loc)
138+
} else {
139+
let property_name = property_class.as_str();
140+
Stmt::block(
141+
vec![
142+
Stmt::assert(cond.clone(), property_name, message, loc),
143+
Stmt::assume(cond, loc),
144+
],
145+
loc,
146+
)
147+
}
141148
}
142149

143150
/// Generate code to cover the given condition at the current location

kani-driver/src/args/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,11 @@ pub struct VerificationArgs {
330330
#[arg(long, hide = true)]
331331
pub print_llbc: bool,
332332

333+
/// Compute verification results under the assumption that no panic occurs.
334+
/// This feature is unstable, and it requires `-Z unstable-options` to be used
335+
#[arg(long, hide_short_help = true)]
336+
pub prove_safety_only: bool,
337+
333338
/// Randomize the layout of structures. This option can help catching code that relies on
334339
/// a specific layout chosen by the compiler that is not guaranteed to be stable in the future.
335340
/// If a value is given, it will be used as the seed for randomization
@@ -726,6 +731,12 @@ impl ValidateArgs for VerificationArgs {
726731
UnstableFeature::FunctionContracts,
727732
)?;
728733

734+
self.common_args.check_unstable(
735+
self.prove_safety_only,
736+
"prove-safety-only",
737+
UnstableFeature::UnstableOptions,
738+
)?;
739+
729740
Ok(())
730741
};
731742

kani-driver/src/call_single_file.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ impl KaniSession {
175175
flags.extend(args.into_iter().map(KaniArg::from));
176176
}
177177

178+
if self.args.prove_safety_only {
179+
flags.push("--prove-safety-only".into());
180+
}
181+
178182
flags.extend(self.args.common_args.unstable_features.as_arguments().map(KaniArg::from));
179183

180184
flags
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//
4+
// kani-flags: -Z unstable-options --prove-safety-only
5+
//! Test that --prove-safety-only works
6+
7+
#[kani::proof]
8+
fn div0() -> i32 {
9+
let x: i32 = kani::any();
10+
let y: i32 = kani::any();
11+
x / y
12+
}
13+
14+
#[kani::proof]
15+
fn assert_hides_ub() {
16+
let arr: [u8; 5] = kani::any();
17+
let mut bytes = kani::slice::any_slice_of_array(&arr);
18+
let slice_offset = unsafe { bytes.as_ptr().offset_from(&arr as *const u8) };
19+
let offset: usize = kani::any();
20+
assert!(offset <= 4 && (slice_offset as usize) + offset <= 4);
21+
let _ = unsafe { *bytes.as_ptr().add(offset) };
22+
}

0 commit comments

Comments
 (0)