Skip to content

Commit 71b0e86

Browse files
Add support for struct field accessing in loop contracts (#3970)
This PR adds support for struct field accessing in loop contracts. Previously, using struct field accessing in loop contracts may result in a panic: ``` internal error: entered unreachable code: The loop invariant support only reference of user variables. The provided invariants contain unsupported dereference. Please report github.com/model-checking/kani/issues/new?template=bug_report.md note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` Resolves #3700 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 f284b34 commit 71b0e86

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

kani-compiler/src/kani_middle/transform/loop_contracts.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use rustc_middle::ty::TyCtxt;
1616
use rustc_span::Symbol;
1717
use stable_mir::mir::mono::Instance;
1818
use stable_mir::mir::{
19-
AggregateKind, BasicBlock, BasicBlockIdx, Body, ConstOperand, Operand, Place, Rvalue,
20-
Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfoContents,
19+
AggregateKind, BasicBlock, BasicBlockIdx, Body, ConstOperand, Operand, Rvalue, Statement,
20+
StatementKind, Terminator, TerminatorKind, VarDebugInfoContents,
2121
};
2222
use stable_mir::ty::{FnDef, MirConst, RigidTy, UintTy};
2323
use std::collections::{HashMap, HashSet, VecDeque};
@@ -295,11 +295,11 @@ impl LoopContractPass {
295295

296296
// Collect supported vars assigned in the block.
297297
// And check if all arguments of the closure is supported.
298-
let mut supported_vars: Vec<Place> = Vec::new();
298+
let mut supported_vars: Vec<usize> = Vec::new();
299299
// All user variables are support
300300
supported_vars.extend(new_body.var_debug_info().iter().filter_map(|info| {
301301
match &info.value {
302-
VarDebugInfoContents::Place(debug_place) => Some(debug_place.clone()),
302+
VarDebugInfoContents::Place(debug_place) => Some(debug_place.local),
303303
_ => None,
304304
}
305305
}));
@@ -310,8 +310,12 @@ impl LoopContractPass {
310310
for stmt in &new_body.blocks()[bb_idx].statements {
311311
if let StatementKind::Assign(place, rvalue) = &stmt.kind {
312312
match rvalue {
313+
Rvalue::Ref(_,_,rplace) => {
314+
if supported_vars.contains(&rplace.local) {
315+
supported_vars.push(place.local);
316+
} }
313317
Rvalue::Aggregate(AggregateKind::Closure(..), closure_args) => {
314-
if closure_args.iter().any(|arg| !matches!(arg, Operand::Copy(arg_place) | Operand::Move(arg_place) if supported_vars.contains(arg_place))) {
318+
if closure_args.iter().any(|arg| !matches!(arg, Operand::Copy(arg_place) | Operand::Move(arg_place) if supported_vars.contains(&arg_place.local))) {
315319
unreachable!(
316320
"The loop invariant support only reference of user variables. The provided invariants contain unsupported dereference. \
317321
Please report github.com/model-checking/kani/issues/new?template=bug_report.md"
@@ -320,7 +324,7 @@ impl LoopContractPass {
320324
}
321325
_ => {
322326
if self.is_supported_argument_of_closure(rvalue, new_body) {
323-
supported_vars.push(place.clone());
327+
supported_vars.push(place.local);
324328
}
325329
}
326330
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
struct_projection.loop_invariant_step.1\
2+
- Status: SUCCESS\
3+
- Description: "Check invariant after step for loop struct_projection.0"
4+
5+
struct_projection.loop_invariant_step.2\
6+
- Status: SUCCESS\
7+
- Description: "Check invariant after step for loop struct_projection.0"
8+
9+
struct_projection.assertion.3\
10+
- Status: SUCCESS\
11+
- Description: "assertion failed: s.b == 2"
12+
13+
14+
VERIFICATION:- SUCCESSFUL
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// kani-flags: -Z loop-contracts
5+
6+
//! add support for struct field projection for loop-contract
7+
8+
#![feature(stmt_expr_attributes)]
9+
#![feature(proc_macro_hygiene)]
10+
11+
struct mystruct {
12+
a: i32,
13+
b: i32,
14+
}
15+
16+
#[kani::proof]
17+
fn struct_projection() {
18+
let mut s = mystruct { a: 0, b: 2 };
19+
let mut i = 0;
20+
#[kani::loop_invariant((i<=10) && (s.a == i) && (s.b == 2))]
21+
while i < 10 {
22+
s.a += 1;
23+
i += 1;
24+
}
25+
assert!(s.b == 2)
26+
}

0 commit comments

Comments
 (0)