#[derive(Arbitrary)]
{
// Attributes available to this derive:
#[safety_constraint]
}
Expand description
Allow users to auto generate Arbitrary
implementations by using
#[derive(Arbitrary)]
macro.
When using #[derive(Arbitrary)]
on a struct, the #[safety_constraint(<cond>)]
attribute can be added to its fields to indicate a type safety invariant
condition <cond>
. Since kani::any()
is always expected to produce
type-safe values, adding #[safety_constraint(...)]
to any fields will further
constrain the objects generated with kani::any()
.
For example, the check_positive
harness in this code is expected to
pass:
#[derive(kani::Arbitrary)]
struct AlwaysPositive {
#[safety_constraint(*inner >= 0)]
inner: i32,
}
#[kani::proof]
fn check_positive() {
let val: AlwaysPositive = kani::any();
assert!(val.inner >= 0);
}
Therefore, using the #[safety_constraint(...)]
attribute can lead to vacuous
results when the values are over-constrained. For example, in this code
the check_positive
harness will pass too:
#[derive(kani::Arbitrary)]
struct AlwaysPositive {
#[safety_constraint(*inner >= 0 && *inner < i32::MIN)]
inner: i32,
}
#[kani::proof]
fn check_positive() {
let val: AlwaysPositive = kani::any();
assert!(val.inner >= 0);
}
Unfortunately, we made a mistake when specifying the condition because
*inner >= 0 && *inner < i32::MIN
is equivalent to false
. This results
in the relevant assertion being unreachable:
Check 1: check_positive.assertion.1
- Status: UNREACHABLE
- Description: "assertion failed: val.inner >= 0"
- Location: src/main.rs:22:5 in function check_positive
As usual, we recommend users to defend against these behaviors by using
kani::cover!(...)
checks and watching out for unreachable assertions in
their project’s code.