Skip to content

Commit d588c01

Browse files
authored
Fix typed_swap for ZSTs (rust-lang#3256)
typed_swap needs to be a no-op on ZSTs as pointers to those have an arbitrary value in Kani. Resolves: rust-lang#3182
1 parent db54783 commit d588c01

File tree

3 files changed

+43
-27
lines changed

3 files changed

+43
-27
lines changed

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

+36-25
Original file line numberDiff line numberDiff line change
@@ -1880,12 +1880,11 @@ impl<'tcx> GotocCtx<'tcx> {
18801880
"`dst` must be properly aligned",
18811881
loc,
18821882
);
1883-
let deref = dst.dereference();
1884-
if deref.typ().sizeof(&self.symbol_table) == 0 {
1883+
if self.is_zst_stable(pointee_type_stable(dst_typ).unwrap()) {
18851884
// do not attempt to dereference (and assign) a ZST
18861885
align_check
18871886
} else {
1888-
let expr = deref.assign(src, loc);
1887+
let expr = dst.dereference().assign(src, loc);
18891888
Stmt::block(vec![align_check, expr], loc)
18901889
}
18911890
}
@@ -1991,30 +1990,42 @@ impl<'tcx> GotocCtx<'tcx> {
19911990
let x = fargs.remove(0);
19921991
let y = fargs.remove(0);
19931992

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);
1993+
if self.is_zst_stable(pointee_type_stable(farg_types[0]).unwrap()) {
1994+
// do not attempt to dereference (and assign) a ZST
1995+
Stmt::skip(loc)
1996+
} else {
1997+
// if(same_object(x, y)) {
1998+
// assert(x + 1 <= y || y + 1 <= x);
1999+
// assume(x + 1 <= y || y + 1 <= x);
2000+
// }
2001+
let one = Expr::int_constant(1, Type::c_int());
2002+
let non_overlapping = x
2003+
.clone()
2004+
.plus(one.clone())
2005+
.le(y.clone())
2006+
.or(y.clone().plus(one.clone()).le(x.clone()));
2007+
let non_overlapping_check = self.codegen_assert_assume(
2008+
non_overlapping,
2009+
PropertyClass::SafetyCheck,
2010+
"memory regions pointed to by `x` and `y` must not overlap",
2011+
loc,
2012+
);
2013+
let non_overlapping_stmt = Stmt::if_then_else(
2014+
x.clone().same_object(y.clone()),
2015+
non_overlapping_check,
2016+
None,
2017+
loc,
2018+
);
20092019

2010-
// T t = *y; *y = *x; *x = t;
2011-
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);
2020+
// T t = *y; *y = *x; *x = t;
2021+
let deref_y = y.clone().dereference();
2022+
let (temp_var, assign_to_t) =
2023+
self.decl_temp_variable(deref_y.typ().clone(), Some(deref_y), loc);
2024+
let assign_to_y = y.dereference().assign(x.clone().dereference(), loc);
2025+
let assign_to_x = x.dereference().assign(temp_var, loc);
20162026

2017-
Stmt::block(vec![non_overlapping_stmt, assign_to_t, assign_to_y, assign_to_x], loc)
2027+
Stmt::block(vec![non_overlapping_stmt, assign_to_t, assign_to_y, assign_to_x], loc)
2028+
}
20182029
}
20192030
}
20202031

tests/kani/Intrinsics/typed_swap.rs

+7
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

-2
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)