Slice comparison/loop unwinding causing extensive kani runtime #125
-
I found that when I try to compare slice values after calling
// pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self
#[kani::proof_for_contract(NonNull::slice_from_raw_parts)]
pub fn non_null_check_slice_from_raw_parts() {
const arr_len: usize = 10;
// Create a non-deterministic array
let mut arr: [i8; arr_len] = kani::any();
// Get a raw NonNull pointer to the start of the slice
let arr_raw_ptr = NonNull::new(arr.as_mut_ptr()).unwrap();
// Create NonNull slice from the start pointer and ends at random slice_len
let slice_len: usize = kani::any(); // if set to 3 kani finishes in 1.3s
kani::assume(slice_len <= arr_len);
let nonnull_slice = NonNull::<[i8]>::slice_from_raw_parts(arr_raw_ptr, slice_len);
// Ensure slice content is preserved, runtime at this step is proportional to arr_len
unsafe {
kani::assert( &arr[..slice_len] == nonnull_slice.as_ref(), "slice content must preserve" );
}
} Contract: //TODO: The entire memory range of this slice must be contained within a single allocated object(same_allocation?)
#[requires(data.pointer.is_aligned()
&& len as isize * core::mem::size_of::<T>() as isize <= isize::MAX
&& (len as isize).checked_mul(core::mem::size_of::<T>() as isize).is_some()
&& (data.pointer as isize).checked_add(len as isize * core::mem::size_of::<T>() as isize).is_some())] // adding len * core::mem::size_of::<T>() to data must not “wrap around” the address space
#[ensures(|result| !result.pointer.is_null())] //TODO: &data[..len] == result.as_ref() preserve content
pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
// SAFETY: `data` is a `NonNull` pointer which is necessarily non-null
unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), len)) }
} For example, when I set
But if I set
I wonder why there is such a drastic difference, especially considering the original array length is only 10. Thank you! @zhassan-aws |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Hi @QinyuanWu. When the array length is constrained via an assumption, i.e. let slice_len: usize = kani::any(); // if set to 3 kani finishes in 1.3s
kani::assume(slice_len <= arr_len); CBMC is unable to determine if the unwinding is sufficient during symbolic execution, hence it keeps unwinding. In this case, an unwind attribute must be specified, e.g. #[kani::proof_for_contract(NonNull::slice_from_raw_parts)]
#[kani::unwind(11)]
pub fn non_null_check_slice_from_raw_parts() { Specifying an unwind value should resolve the issue. |
Beta Was this translation helpful? Give feedback.
Hi @QinyuanWu. When the array length is constrained via an assumption, i.e.
CBMC is unable to determine if the unwinding is sufficient during symbolic execution, hence it keeps unwinding. In this case, an unwind attribute must be specified, e.g.
Specifying an unwind value should resolve the issue.