Skip to content

Commit b18698f

Browse files
authored
Add missing functionalities to kani_core (rust-lang#3384)
- Add Arbitrary for array - Add Arbitrary for tuples - Add missing changes from modifies slices (rust-lang#3295) Note that for adding `any_array` I had to cleanup the unnecessary usage of constant parameters from `kani::any_raw`.
1 parent 114beea commit b18698f

File tree

9 files changed

+209
-134
lines changed

9 files changed

+209
-134
lines changed

library/kani/src/arbitrary.rs

+4-20
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ where
1616
Self: Sized,
1717
{
1818
fn any() -> Self;
19-
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH]
20-
// the requirement defined in the where clause must appear on the `impl`'s method `any_array`
21-
// but also on the corresponding trait's method
22-
where
23-
[(); std::mem::size_of::<[Self; MAX_ARRAY_LENGTH]>()]:,
24-
{
19+
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH] {
2520
[(); MAX_ARRAY_LENGTH].map(|_| Self::any())
2621
}
2722
}
@@ -33,20 +28,10 @@ macro_rules! trivial_arbitrary {
3328
#[inline(always)]
3429
fn any() -> Self {
3530
// This size_of call does not use generic_const_exprs feature. It's inside a macro, and Self isn't generic.
36-
unsafe { crate::any_raw_internal::<Self, { std::mem::size_of::<Self>() }>() }
31+
unsafe { crate::any_raw_internal::<Self>() }
3732
}
38-
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH]
39-
where
40-
// `generic_const_exprs` requires all potential errors to be reflected in the signature/header.
41-
// We must repeat the expression in the header, to make sure that if the body can fail the header will also fail.
42-
[(); { std::mem::size_of::<[$type; MAX_ARRAY_LENGTH]>() }]:,
43-
{
44-
unsafe {
45-
crate::any_raw_internal::<
46-
[Self; MAX_ARRAY_LENGTH],
47-
{ std::mem::size_of::<[Self; MAX_ARRAY_LENGTH]>() },
48-
>()
49-
}
33+
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH] {
34+
unsafe { crate::any_raw_internal::<[Self; MAX_ARRAY_LENGTH]>() }
5035
}
5136
}
5237
};
@@ -128,7 +113,6 @@ nonzero_arbitrary!(NonZeroIsize, isize);
128113
impl<T, const N: usize> Arbitrary for [T; N]
129114
where
130115
T: Arbitrary,
131-
[(); std::mem::size_of::<[T; N]>()]:,
132116
{
133117
fn any() -> Self {
134118
T::any_array()

library/kani/src/concrete_playback.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,17 @@ pub fn concrete_playback_run<F: Fn()>(mut local_concrete_vals: Vec<Vec<u8>>, pro
4747
/// # Safety
4848
///
4949
/// The semantics of this function require that SIZE_T equals the size of type T.
50-
pub(crate) unsafe fn any_raw_internal<T, const SIZE_T: usize>() -> T {
50+
pub(crate) unsafe fn any_raw_internal<T: Copy>() -> T {
51+
let sz = size_of::<T>();
5152
let mut next_concrete_val: Vec<u8> = Vec::new();
5253
CONCRETE_VALS.with(|glob_concrete_vals| {
5354
let mut_ref_glob_concrete_vals = &mut *glob_concrete_vals.borrow_mut();
54-
next_concrete_val = if SIZE_T > 0 {
55+
next_concrete_val = if sz > 0 {
5556
mut_ref_glob_concrete_vals.pop().expect("Not enough det vals found")
5657
} else {
5758
vec![]
5859
};
5960
});
60-
let next_concrete_val_len = next_concrete_val.len();
61-
let bytes_t: [u8; SIZE_T] = next_concrete_val.try_into().expect(&format!(
62-
"Expected {SIZE_T} bytes instead of {next_concrete_val_len} bytes in the following det vals vec"
63-
));
64-
std::mem::transmute_copy::<[u8; SIZE_T], T>(&bytes_t)
61+
assert_eq!(next_concrete_val.len(), sz, "Expected {sz} bytes in the following det vals vec");
62+
unsafe { *(next_concrete_val.as_ptr() as *mut T) }
6563
}

library/kani/src/lib.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
// Used for rustc_diagnostic_item.
88
// Note: We could use a kanitool attribute instead.
99
#![feature(rustc_attrs)]
10-
// This is required for the optimized version of `any_array()`
11-
#![feature(generic_const_exprs)]
12-
#![allow(incomplete_features)]
1310
// Used to model simd.
1411
#![feature(repr_simd)]
12+
#![feature(generic_const_exprs)]
13+
#![allow(incomplete_features)]
1514
// Features used for tests only.
1615
#![cfg_attr(test, feature(core_intrinsics, portable_simd))]
1716
// Required for `rustc_diagnostic_item` and `core_intrinsics`
@@ -21,6 +20,9 @@
2120
#![feature(f16)]
2221
#![feature(f128)]
2322

23+
// Allow us to use `kani::` to access crate features.
24+
extern crate self as kani;
25+
2426
pub mod arbitrary;
2527
#[cfg(feature = "concrete_playback")]
2628
mod concrete_playback;
@@ -48,6 +50,7 @@ pub use invariant::Invariant;
4850
pub fn concrete_playback_run<F: Fn()>(_: Vec<Vec<u8>>, _: F) {
4951
unreachable!("Concrete playback does not work during verification")
5052
}
53+
5154
pub use futures::{block_on, block_on_with_spawn, spawn, yield_now, RoundRobin};
5255

5356
/// Creates an assumption that will be valid after this statement run. Note that the assumption
@@ -246,21 +249,21 @@ pub fn any_where<T: Arbitrary, F: FnOnce(&T) -> bool>(f: F) -> T {
246249
/// Note that SIZE_T must be equal the size of type T in bytes.
247250
#[inline(never)]
248251
#[cfg(not(feature = "concrete_playback"))]
249-
pub(crate) unsafe fn any_raw_internal<T, const SIZE_T: usize>() -> T {
252+
pub(crate) unsafe fn any_raw_internal<T: Copy>() -> T {
250253
any_raw_inner::<T>()
251254
}
252255

253256
#[inline(never)]
254257
#[cfg(feature = "concrete_playback")]
255-
pub(crate) unsafe fn any_raw_internal<T, const SIZE_T: usize>() -> T {
256-
concrete_playback::any_raw_internal::<T, SIZE_T>()
258+
pub(crate) unsafe fn any_raw_internal<T: Copy>() -> T {
259+
concrete_playback::any_raw_internal::<T>()
257260
}
258261

259262
/// This low-level function returns nondet bytes of size T.
260263
#[rustc_diagnostic_item = "KaniAnyRaw"]
261264
#[inline(never)]
262265
#[allow(dead_code)]
263-
fn any_raw_inner<T>() -> T {
266+
fn any_raw_inner<T: Copy>() -> T {
264267
kani_intrinsic()
265268
}
266269

library/kani/src/vec.rs

-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use crate::{any, any_where, Arbitrary};
66
pub fn any_vec<T, const MAX_LENGTH: usize>() -> Vec<T>
77
where
88
T: Arbitrary,
9-
[(); std::mem::size_of::<[T; MAX_LENGTH]>()]:,
109
{
1110
let real_length: usize = any_where(|sz| *sz <= MAX_LENGTH);
1211
match real_length {
@@ -26,7 +25,6 @@ where
2625
pub fn exact_vec<T, const EXACT_LENGTH: usize>() -> Vec<T>
2726
where
2827
T: Arbitrary,
29-
[(); std::mem::size_of::<[T; EXACT_LENGTH]>()]:,
3028
{
3129
let boxed_array: Box<[T; EXACT_LENGTH]> = Box::new(any());
3230
<[T]>::into_vec(boxed_array)

library/kani_core/src/arbitrary.rs

+40-30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//!
99
//! TODO: Use this inside kani library so that we dont have to maintain two copies of the same proc macro for arbitrary.
1010
#[macro_export]
11+
#[allow(clippy::crate_in_macro_def)]
1112
macro_rules! generate_arbitrary {
1213
($core:path) => {
1314
use core_path::marker::{PhantomData, PhantomPinned};
@@ -18,13 +19,7 @@ macro_rules! generate_arbitrary {
1819
Self: Sized,
1920
{
2021
fn any() -> Self;
21-
#[cfg(kani_sysroot)]
22-
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH]
23-
// the requirement defined in the where clause must appear on the `impl`'s method `any_array`
24-
// but also on the corresponding trait's method
25-
where
26-
[(); core_path::mem::size_of::<[Self; MAX_ARRAY_LENGTH]>()]:,
27-
{
22+
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH] {
2823
[(); MAX_ARRAY_LENGTH].map(|_| Self::any())
2924
}
3025
}
@@ -36,22 +31,10 @@ macro_rules! generate_arbitrary {
3631
#[inline(always)]
3732
fn any() -> Self {
3833
// This size_of call does not use generic_const_exprs feature. It's inside a macro, and Self isn't generic.
39-
unsafe { any_raw_internal::<Self, { core_path::mem::size_of::<Self>() }>() }
34+
unsafe { crate::kani::any_raw_internal::<Self>() }
4035
}
41-
// Disable this for standard library since we cannot enable generic constant expr.
42-
#[cfg(kani_sysroot)]
43-
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH]
44-
where
45-
// `generic_const_exprs` requires all potential errors to be reflected in the signature/header.
46-
// We must repeat the expression in the header, to make sure that if the body can fail the header will also fail.
47-
[(); { core_path::mem::size_of::<[$type; MAX_ARRAY_LENGTH]>() }]:,
48-
{
49-
unsafe {
50-
any_raw_internal::<
51-
[Self; MAX_ARRAY_LENGTH],
52-
{ core_path::mem::size_of::<[Self; MAX_ARRAY_LENGTH]>() },
53-
>()
54-
}
36+
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH] {
37+
unsafe { crate::kani::any_raw_internal::<[Self; MAX_ARRAY_LENGTH]>() }
5538
}
5639
}
5740
};
@@ -134,6 +117,15 @@ macro_rules! generate_arbitrary {
134117
}
135118
}
136119

120+
impl<T, const N: usize> Arbitrary for [T; N]
121+
where
122+
T: Arbitrary,
123+
{
124+
fn any() -> Self {
125+
T::any_array::<N>()
126+
}
127+
}
128+
137129
impl<T> Arbitrary for Option<T>
138130
where
139131
T: Arbitrary,
@@ -165,15 +157,33 @@ macro_rules! generate_arbitrary {
165157
}
166158
}
167159

168-
#[cfg(kani_sysroot)]
169-
impl<T, const N: usize> Arbitrary for [T; N]
170-
where
171-
T: Arbitrary,
172-
[(); core_path::mem::size_of::<[T; N]>()]:,
173-
{
160+
arbitrary_tuple!(A);
161+
arbitrary_tuple!(A, B);
162+
arbitrary_tuple!(A, B, C);
163+
arbitrary_tuple!(A, B, C, D);
164+
arbitrary_tuple!(A, B, C, D, E);
165+
arbitrary_tuple!(A, B, C, D, E, F);
166+
arbitrary_tuple!(A, B, C, D, E, F, G);
167+
arbitrary_tuple!(A, B, C, D, E, F, G, H);
168+
arbitrary_tuple!(A, B, C, D, E, F, G, H, I);
169+
arbitrary_tuple!(A, B, C, D, E, F, G, H, I, J);
170+
arbitrary_tuple!(A, B, C, D, E, F, G, H, I, J, K);
171+
arbitrary_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
172+
};
173+
}
174+
175+
/// This macro implements `kani::Arbitrary` on a tuple whose elements
176+
/// already implement `kani::Arbitrary` by running `kani::any()` on
177+
/// each index of the tuple.
178+
#[allow(clippy::crate_in_macro_def)]
179+
#[macro_export]
180+
macro_rules! arbitrary_tuple {
181+
($($type:ident),*) => {
182+
impl<$($type : Arbitrary),*> Arbitrary for ($($type,)*) {
183+
#[inline(always)]
174184
fn any() -> Self {
175-
T::any_array()
185+
($(crate::kani::any::<$type>(),)*)
176186
}
177187
}
178-
};
188+
}
179189
}

0 commit comments

Comments
 (0)