Skip to content

Commit 8480dc6

Browse files
authored
Deprecate any_slice (rust-lang#2789)
Deprecate kani::slice::any_slice in Kani 0.38.0 (and the related AnySlice struct), and remove it in a later version. Motivation: The Kani library's `slice::any_slice` API is doing more harm than benefit: it is meant to provide a convenient way for users to generate non-deterministic slices, but its current implementation aims to avoid any unsoundness by making sure that for the non-deterministic slice returned by the API, accessing memory beyond the slice length is flagged as an out-of-bounds access (see rust-lang#1009 for details). However, in practical scenarios, using it ends up causing memory to blowup for CBMC. Given that users may not care about this type of unsoundness, which is only possible through using a pointer dereference inside an unsafe block (see discussion in rust-lang#2634). Thus, we should leave it to the user to decide the suitable method for generating slices that fits their verification needs. For example, they can use Kani's alternative API, `any_slice_of_array` that extracts a slice of a non-deterministic start and end from a given array.
1 parent 6b1a09d commit 8480dc6

File tree

11 files changed

+62
-66
lines changed

11 files changed

+62
-66
lines changed

library/kani/src/slice.rs

+14
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,17 @@ fn any_range<const LENGTH: usize>() -> (usize, usize) {
4747
/// let slice: kani::slice::AnySlice<u8, 5> = kani::slice::any_slice();
4848
/// foo(&slice); // where foo is a function that takes a slice and verifies a property about it
4949
/// ```
50+
#[deprecated(
51+
since = "0.38.0",
52+
note = "Use `any_slice_of_array` or `any_slice_of_array_mut` instead"
53+
)]
5054
pub struct AnySlice<T, const MAX_SLICE_LENGTH: usize> {
5155
layout: Layout,
5256
ptr: *mut T,
5357
slice_len: usize,
5458
}
5559

60+
#[allow(deprecated)]
5661
impl<T, const MAX_SLICE_LENGTH: usize> AnySlice<T, MAX_SLICE_LENGTH> {
5762
fn new() -> Self
5863
where
@@ -103,6 +108,7 @@ impl<T, const MAX_SLICE_LENGTH: usize> AnySlice<T, MAX_SLICE_LENGTH> {
103108
}
104109
}
105110

111+
#[allow(deprecated)]
106112
impl<T, const MAX_SLICE_LENGTH: usize> Drop for AnySlice<T, MAX_SLICE_LENGTH> {
107113
fn drop(&mut self) {
108114
if self.slice_len > 0 {
@@ -114,6 +120,7 @@ impl<T, const MAX_SLICE_LENGTH: usize> Drop for AnySlice<T, MAX_SLICE_LENGTH> {
114120
}
115121
}
116122

123+
#[allow(deprecated)]
117124
impl<T, const MAX_SLICE_LENGTH: usize> Deref for AnySlice<T, MAX_SLICE_LENGTH> {
118125
type Target = [T];
119126

@@ -122,15 +129,22 @@ impl<T, const MAX_SLICE_LENGTH: usize> Deref for AnySlice<T, MAX_SLICE_LENGTH> {
122129
}
123130
}
124131

132+
#[allow(deprecated)]
125133
impl<T, const MAX_SLICE_LENGTH: usize> DerefMut for AnySlice<T, MAX_SLICE_LENGTH> {
126134
fn deref_mut(&mut self) -> &mut Self::Target {
127135
self.get_slice_mut()
128136
}
129137
}
130138

139+
#[deprecated(
140+
since = "0.38.0",
141+
note = "Use `any_slice_of_array` or `any_slice_of_array_mut` instead"
142+
)]
143+
#[allow(deprecated)]
131144
pub fn any_slice<T, const MAX_SLICE_LENGTH: usize>() -> AnySlice<T, MAX_SLICE_LENGTH>
132145
where
133146
T: Arbitrary,
134147
{
148+
#[allow(deprecated)]
135149
AnySlice::<T, MAX_SLICE_LENGTH>::new()
136150
}

tests/expected/nondet-slice-i32-oob/main.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
// This test checks that Kani reports out-of-bound accesses on a non-det slice
5-
// created using kani::slice::any_slice
5+
// created using `kani::slice::any_slice_of_array`
66

77
#[kani::proof]
88
fn check_out_of_bounds() {
9-
let bytes = kani::slice::any_slice::<i32, 8>();
10-
let val = unsafe { *bytes.get_slice().as_ptr().offset(1) };
9+
let arr: [i32; 8] = kani::any();
10+
let bytes = kani::slice::any_slice_of_array(&arr);
11+
let val = unsafe { *bytes.as_ptr().offset(1) };
1112
assert_eq!(val - val, 0);
1213
}
+14-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
Failed Checks: assertion failed: s.len() != 0
2-
Failed Checks: assertion failed: s.len() != 1
3-
Failed Checks: assertion failed: s.len() != 2
4-
Failed Checks: assertion failed: s.len() != 3
5-
Failed Checks: assertion failed: s.len() != 4
1+
Status: SATISFIED\
2+
Description: "cover condition: s.len() == 0"
3+
4+
Status: SATISFIED\
5+
Description: "cover condition: s.len() == 1"
6+
7+
Status: SATISFIED\
8+
Description: "cover condition: s.len() == 2"
9+
10+
Status: SATISFIED\
11+
Description: "cover condition: s.len() == 3"
12+
13+
Status: SATISFIED\
14+
Description: "cover condition: s.len() == 4"
+8-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
// Copyright Kani Contributors
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

4-
// This test checks that non-det slices created using kani::slice::any_slice can
4+
// This test checks that non-det slices created using `kani::slice::any_slice_of_array`
55
// assume any length up the specified maximum
66

77
#[kani::proof]
88
fn check_possible_slice_lengths() {
9-
let s = kani::slice::any_slice::<i32, 4>();
10-
assert!(s.len() != 0);
11-
assert!(s.len() != 1);
12-
assert!(s.len() != 2);
13-
assert!(s.len() != 3);
14-
assert!(s.len() != 4);
9+
let arr: [i32; 4] = kani::any();
10+
let s = kani::slice::any_slice_of_array(&arr);
11+
kani::cover!(s.len() == 0);
12+
kani::cover!(s.len() == 1);
13+
kani::cover!(s.len() == 2);
14+
kani::cover!(s.len() == 3);
15+
kani::cover!(s.len() == 4);
1516
}

tests/expected/nondet-slice-u8-oob/main.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
// This test checks that Kani reports out-of-bound accesses on a non-det slice
5-
// created using kani::slice::any_slice
5+
// created using `kani::slice::any_slice_of_array`
66

77
#[kani::proof]
88
fn check_out_of_bounds() {
9-
let mut bytes = kani::slice::any_slice::<u8, 5>();
10-
let val = unsafe { *bytes.get_slice().as_ptr().add(4) };
9+
let arr: [u8; 5] = kani::any();
10+
let mut bytes = kani::slice::any_slice_of_array(&arr);
11+
let val = unsafe { *bytes.as_ptr().add(4) };
1112
kani::assume(val != 0);
1213
assert_ne!(val, 0);
1314
}

tests/kani/NondetSlices/test2.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ fn check(s: &[u8]) {
99

1010
#[kani::proof]
1111
fn main() {
12-
// returns a slice of length between 0 and 5 with non-det content
13-
let slice: kani::slice::AnySlice<u8, 5> = kani::slice::any_slice();
12+
let arr: [u8; 5] = kani::any();
13+
// returns a slice of length between 0 and 5
14+
let slice = kani::slice::any_slice_of_array(&arr);
1415
check(&slice);
1516
}

tests/kani/NondetSlices/test3.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// Copyright Kani Contributors
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

4-
// This test uses kani::slice::any_slice of i32
4+
// This test uses `kani::slice::any_slice_of_array` with `i32`
55

66
// kani-flags: --default-unwind 6
77

88
#[kani::proof]
99
fn check_any_slice_i32() {
10-
let s = kani::slice::any_slice::<i32, 5>();
10+
let a: [i32; 5] = kani::any();
11+
let s = kani::slice::any_slice_of_array(&a);
1112
s.iter().for_each(|x| kani::assume(*x < 10 && *x > -20));
1213
let sum = s.iter().fold(0, |acc, x| acc + x);
1314
assert!(sum <= 45); // 9 * 5

tests/kani/NondetSlices/test4.rs

-19
This file was deleted.

tests/kani/Slice/slice-drop.rs

-25
This file was deleted.
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
warning: use of deprecated function `kani::slice::any_slice`: Use `any_slice_of_array` or `any_slice_of_array_mut` instead
2+
warning: use of deprecated struct `kani::slice::AnySlice`: Use `any_slice_of_array` or `any_slice_of_array_mut` instead

tests/ui/any-slice-deprecated/test.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! A test that checks that Kani emits the deprecated message for `any_slice`
5+
//! and `AnySlice`
6+
7+
#[kani::proof]
8+
fn check_any_slice_deprecated() {
9+
let _s: kani::slice::AnySlice<i32, 5> = kani::slice::any_slice();
10+
}

0 commit comments

Comments
 (0)