Skip to content

Commit 603d647

Browse files
Fix bug: goto-cc crash when there are two quantifers in one proof (#4221)
This PR allows multiple quantifiers in the same harness. Thanks @tautschnig for fixing the bug from CBMC side. Resolves #4020 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 4da64f3 commit 603d647

File tree

5 files changed

+98
-6
lines changed

5 files changed

+98
-6
lines changed

kani-compiler/src/codegen_cprover_gotoc/context/goto_ctx.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,11 @@ impl GotocCtx<'_> {
318318
pub fn handle_quantifiers(&mut self) {
319319
// Store the found quantifiers and the inlined results.
320320
let mut to_modify: BTreeMap<InternedString, SymbolValues> = BTreeMap::new();
321+
let mut suffix_count: u16 = 0;
321322
for (key, symbol) in self.symbol_table.iter() {
322323
if let SymbolValues::Stmt(stmt) = &symbol.value {
323-
let new_stmt_val = SymbolValues::Stmt(self.handle_quantifiers_in_stmt(stmt));
324+
let new_stmt_val =
325+
SymbolValues::Stmt(self.handle_quantifiers_in_stmt(stmt, &mut suffix_count));
324326
to_modify.insert(*key, new_stmt_val);
325327
}
326328
}
@@ -332,7 +334,7 @@ impl GotocCtx<'_> {
332334
}
333335

334336
/// Find all quantifier expressions in `stmt` and recursively inline functions.
335-
fn handle_quantifiers_in_stmt(&self, stmt: &Stmt) -> Stmt {
337+
fn handle_quantifiers_in_stmt(&self, stmt: &Stmt, suffix_count: &mut u16) -> Stmt {
336338
match &stmt.body() {
337339
// According to the hook handling for quantifiers, quantifier expressions must be of form
338340
// lhs = typecast(qex, c_bool)
@@ -345,13 +347,13 @@ impl GotocCtx<'_> {
345347
let mut visited_func_symbols: HashSet<InternedString> = HashSet::new();
346348
// We count the number of function that we have inlined, and use the count to
347349
// make inlined labeled unique.
348-
let mut suffix_count: u16 = 0;
350+
//let mut suffix_count: u16 = 0;
349351

350352
let end_stmt = Stmt::code_expression(
351353
self.inline_function_calls_in_expr(
352354
domain,
353355
&mut visited_func_symbols,
354-
&mut suffix_count,
356+
suffix_count,
355357
)
356358
.unwrap(),
357359
*domain.location(),
@@ -406,11 +408,14 @@ impl GotocCtx<'_> {
406408
}
407409
// Recursively find quantifier expressions.
408410
StmtBody::Block(stmts) => Stmt::block(
409-
stmts.iter().map(|stmt| self.handle_quantifiers_in_stmt(stmt)).collect(),
411+
stmts
412+
.iter()
413+
.map(|stmt| self.handle_quantifiers_in_stmt(stmt, suffix_count))
414+
.collect(),
410415
*stmt.location(),
411416
),
412417
StmtBody::Label { label, body } => {
413-
self.handle_quantifiers_in_stmt(body).with_label(*label)
418+
self.handle_quantifiers_in_stmt(body, suffix_count).with_label(*label)
414419
}
415420
_ => stmt.clone(),
416421
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
main.assertion.2\
2+
- Status: SUCCESS\
3+
- Description: "assertion failed: kani::exists!(| i in (0, len) |\
4+
*rebuilt_ptr.wrapping_byte_offset(4*i as isize) == 0)"
5+
6+
VERIFICATION:- SUCCESSFUL
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: -Z quantifiers
4+
5+
/// Example of code using multiple quantifiers
6+
use std::mem;
7+
8+
#[kani::proof]
9+
fn main() {
10+
let original_v = vec![kani::any::<u32>(); 3];
11+
let v = original_v.clone();
12+
let v_len = v.len();
13+
let v_ptr = v.as_ptr();
14+
unsafe {
15+
kani::assume(
16+
kani::forall!(|i in (0,v_len) | *v_ptr.wrapping_byte_offset(4*i as isize) < 5),
17+
);
18+
}
19+
20+
// Prevent running `v`'s destructor so we are in complete control
21+
// of the allocation.
22+
let mut v = mem::ManuallyDrop::new(v);
23+
24+
// Pull out the various important pieces of information about `v`
25+
let p = v.as_mut_ptr();
26+
let len = v.len();
27+
let cap = v.capacity();
28+
29+
unsafe {
30+
// Overwrite memory
31+
for i in 0..len {
32+
*p.add(i) += 1;
33+
if i == 1 {
34+
*p.add(i) = 0;
35+
}
36+
}
37+
38+
// Put everything back together into a Vec
39+
let rebuilt = Vec::from_raw_parts(p, len, cap);
40+
let rebuilt_ptr = v.as_ptr();
41+
assert!(
42+
kani::exists!(| i in (0, len) | *rebuilt_ptr.wrapping_byte_offset(4*i as isize) == 0)
43+
);
44+
}
45+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
main.assertion.1\
2+
- Status: SUCCESS\
3+
- Description: "assertion failed: quan1"
4+
5+
main.assertion.2\
6+
- Status: SUCCESS\
7+
- Description: "assertion failed: quan2"
8+
9+
main.assertion.3\
10+
- Status: SUCCESS\
11+
- Description: "assertion failed: quan3"
12+
13+
14+
main.assertion.4\
15+
- Status: SUCCESS\
16+
- Description: "assertion failed: quan4"
17+
18+
VERIFICATION:- SUCCESSFUL
19+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: -Z quantifiers
4+
5+
/// Example of code using multiple quantifiers
6+
7+
#[kani::proof]
8+
fn main() {
9+
let quan1 = kani::forall!(|i in (4, 100)| i < 1000);
10+
let quan2 = kani::forall!(|i in (2, 6)| i < 7 );
11+
let quan3 = kani::exists!(|i in (0, 10)| i == 8);
12+
let quan4 = kani::exists!(|i in (0, 9)| i % 2 == 0);
13+
assert!(quan1);
14+
assert!(quan2);
15+
assert!(quan3);
16+
assert!(quan4);
17+
}

0 commit comments

Comments
 (0)