Skip to content

Commit df86d33

Browse files
committed
Fix typed_swap for ZSTs
typed_swap needs to be a no-op on ZSTs as pointers to those have an arbitrary value in Kani. Resolves: model-checking#3182
1 parent e922d73 commit df86d33

File tree

3 files changed

+41
-24
lines changed

3 files changed

+41
-24
lines changed

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

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,30 +1991,42 @@ impl<'tcx> GotocCtx<'tcx> {
19911991
let x = fargs.remove(0);
19921992
let y = fargs.remove(0);
19931993

1994-
// if(same_object(x, y)) {
1995-
// assert(x + 1 <= y || y + 1 <= x);
1996-
// assume(x + 1 <= y || y + 1 <= x);
1997-
// }
1998-
let one = Expr::int_constant(1, Type::c_int());
1999-
let non_overlapping =
2000-
x.clone().plus(one.clone()).le(y.clone()).or(y.clone().plus(one.clone()).le(x.clone()));
2001-
let non_overlapping_check = self.codegen_assert_assume(
2002-
non_overlapping,
2003-
PropertyClass::SafetyCheck,
2004-
"memory regions pointed to by `x` and `y` must not overlap",
2005-
loc,
2006-
);
2007-
let non_overlapping_stmt =
2008-
Stmt::if_then_else(x.clone().same_object(y.clone()), non_overlapping_check, None, loc);
2009-
2010-
// T t = *y; *y = *x; *x = t;
20111994
let deref_y = y.clone().dereference();
2012-
let (temp_var, assign_to_t) =
2013-
self.decl_temp_variable(deref_y.typ().clone(), Some(deref_y), loc);
2014-
let assign_to_y = y.dereference().assign(x.clone().dereference(), loc);
2015-
let assign_to_x = x.dereference().assign(temp_var, loc);
1995+
if deref_y.typ().sizeof(&self.symbol_table) == 0 {
1996+
// do not attempt to dereference (and assign) a ZST
1997+
Stmt::skip(loc)
1998+
} else {
1999+
// if(same_object(x, y)) {
2000+
// assert(x + 1 <= y || y + 1 <= x);
2001+
// assume(x + 1 <= y || y + 1 <= x);
2002+
// }
2003+
let one = Expr::int_constant(1, Type::c_int());
2004+
let non_overlapping = x
2005+
.clone()
2006+
.plus(one.clone())
2007+
.le(y.clone())
2008+
.or(y.clone().plus(one.clone()).le(x.clone()));
2009+
let non_overlapping_check = self.codegen_assert_assume(
2010+
non_overlapping,
2011+
PropertyClass::SafetyCheck,
2012+
"memory regions pointed to by `x` and `y` must not overlap",
2013+
loc,
2014+
);
2015+
let non_overlapping_stmt = Stmt::if_then_else(
2016+
x.clone().same_object(y.clone()),
2017+
non_overlapping_check,
2018+
None,
2019+
loc,
2020+
);
2021+
2022+
// T t = *y; *y = *x; *x = t;
2023+
let (temp_var, assign_to_t) =
2024+
self.decl_temp_variable(deref_y.typ().clone(), Some(deref_y), loc);
2025+
let assign_to_y = y.dereference().assign(x.clone().dereference(), loc);
2026+
let assign_to_x = x.dereference().assign(temp_var, loc);
20162027

2017-
Stmt::block(vec![non_overlapping_stmt, assign_to_t, assign_to_y, assign_to_x], loc)
2028+
Stmt::block(vec![non_overlapping_stmt, assign_to_t, assign_to_y, assign_to_x], loc)
2029+
}
20182030
}
20192031
}
20202032

tests/kani/Intrinsics/typed_swap.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,10 @@ fn test_typed_swap_u32() {
1919
assert!(b == a_before);
2020
assert!(a == b_before);
2121
}
22+
23+
#[kani::proof]
24+
pub fn check_swap_unit() {
25+
let mut x: () = kani::any();
26+
let mut y: () = kani::any();
27+
std::mem::swap(&mut x, &mut y)
28+
}

tests/std-checks/core/src/mem.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ mod verify {
4545

4646
/// FIX-ME: Modifies clause fail with pointer to ZST.
4747
/// <https://github.com/model-checking/kani/issues/3181>
48-
/// FIX-ME: `typed_swap` intrisic fails for ZST.
49-
/// <https://github.com/model-checking/kani/issues/3182>
5048
#[kani::proof_for_contract(contracts::swap)]
5149
pub fn check_swap_unit() {
5250
let mut x: () = kani::any();

0 commit comments

Comments
 (0)