Skip to content

Commit eb62ad8

Browse files
authored
Force any_vec capacity to match length (rust-lang#2765)
1 parent 04c7451 commit eb62ad8

File tree

5 files changed

+156
-7
lines changed

5 files changed

+156
-7
lines changed

library/kani/src/vec.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
// Copyright Kani Contributors
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
3-
use crate::{any, assume, Arbitrary};
3+
use crate::{any, any_where, Arbitrary};
44

55
/// Generates an arbitrary vector whose length is at most MAX_LENGTH.
66
pub fn any_vec<T, const MAX_LENGTH: usize>() -> Vec<T>
77
where
88
T: Arbitrary,
99
[(); std::mem::size_of::<[T; MAX_LENGTH]>()]:,
1010
{
11-
let mut v = exact_vec::<T, MAX_LENGTH>();
12-
let real_length: usize = any();
13-
assume(real_length <= MAX_LENGTH);
14-
unsafe { v.set_len(real_length) };
15-
16-
v
11+
let real_length: usize = any_where(|sz| *sz <= MAX_LENGTH);
12+
match real_length {
13+
0 => vec![],
14+
exact if exact == MAX_LENGTH => exact_vec::<T, MAX_LENGTH>(),
15+
_ => {
16+
let mut any_vec = exact_vec::<T, MAX_LENGTH>();
17+
any_vec.truncate(real_length);
18+
any_vec.shrink_to_fit();
19+
assert!(any_vec.capacity() == any_vec.len());
20+
any_vec
21+
}
22+
}
1723
}
1824

1925
/// Generates an arbitrary vector that is exactly EXACT_LENGTH long.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Checking harness check_access_length_17...
2+
3+
Failed Checks: dereference failure: pointer outside object bounds\
4+
in check_access_length_17
5+
6+
Checking harness check_access_length_zero...
7+
8+
Failed Checks: dereference failure: pointer outside object bounds\
9+
in check_access_length_zero
10+
11+
Verification failed for - check_access_length_17
12+
Verification failed for - check_access_length_zero
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! Test `exact_vec` API
5+
#[kani::proof]
6+
fn check_access_length_zero() {
7+
let data = kani::vec::exact_vec::<u8, 0>();
8+
assert_eq!(data.len(), 0);
9+
assert_eq!(data.capacity(), data.len());
10+
let val = unsafe { *data.get_unchecked(0) };
11+
kani::cover!(val == 0);
12+
}
13+
14+
#[derive(kani::Arbitrary, Copy, Clone)]
15+
struct Dummy(i32, u8);
16+
17+
#[kani::proof]
18+
fn check_access_length_17() {
19+
let data = kani::vec::exact_vec::<Dummy, 17>();
20+
assert_eq!(data.len(), 17);
21+
assert_eq!(data.capacity(), data.len());
22+
23+
let val = unsafe { *data.get_unchecked(17) };
24+
kani::cover!(val.0 == 0);
25+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
check_always_out_bounds::check_0.pointer_dereference\
2+
Status: FAILURE\
3+
Description: "dereference failure: pointer NULL"\
4+
function check_always_out_bounds::check_0
5+
6+
check_always_out_bounds::check_0.pointer_dereference\
7+
Status: FAILURE\
8+
Description: "dereference failure: pointer outside object bounds"\
9+
function check_always_out_bounds::check_0
10+
11+
check_always_out_bounds::check_0.pointer_dereference\
12+
Status: FAILURE\
13+
Description: "dereference failure: invalid integer address"\
14+
function check_always_out_bounds::check_0
15+
16+
check_always_out_bounds::check_1.pointer_dereference\
17+
Status: FAILURE\
18+
Description: "dereference failure: pointer outside object bounds"\
19+
function check_always_out_bounds::check_1
20+
21+
check_always_out_bounds::check_2.pointer_dereference\
22+
Status: FAILURE\
23+
Description: "dereference failure: pointer outside object bounds"\
24+
function check_always_out_bounds::check_2
25+
26+
check_always_out_bounds::check_3.pointer_dereference\
27+
Status: FAILURE\
28+
Description: "dereference failure: pointer outside object bounds"\
29+
function check_always_out_bounds::check_3
30+
31+
check_always_out_bounds::check_4.pointer_dereference\
32+
Status: FAILURE\
33+
Description: "dereference failure: pointer outside object bounds"\
34+
function check_always_out_bounds::check_4
35+
36+
check_always_out_bounds::check_5.pointer_dereference\
37+
Status: FAILURE\
38+
Description: "dereference failure: pointer outside object bounds"\
39+
function check_always_out_bounds::check_5
40+
41+
check_always_out_bounds::check_6.pointer_dereference\
42+
Status: FAILURE\
43+
Description: "dereference failure: pointer outside object bounds"\
44+
function check_always_out_bounds::check_6
45+
46+
check_always_out_bounds::check_7.pointer_dereference\
47+
Status: FAILURE\
48+
Description: "dereference failure: pointer outside object bounds"\
49+
function check_always_out_bounds::check_7
50+
51+
check_always_out_bounds::check_8.pointer_dereference\
52+
Status: FAILURE\
53+
Description: "dereference failure: pointer outside object bounds"\
54+
function check_always_out_bounds::check_8
55+
56+
check_always_out_bounds::check_9.cover\
57+
Status: UNREACHABLE\
58+
Description: "cover condition: *val == 0"\
59+
function check_always_out_bounds::check_9
60+
61+

tests/expected/any_vec/out_bounds.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! Test for #2759: Kani does not flag out-of-bounds dereference with `kani::vec::any_vec`
5+
//! <https://github.com/model-checking/kani/issues/2759>
6+
extern crate kani;
7+
use kani::cover;
8+
9+
#[kani::proof]
10+
#[kani::unwind(22)]
11+
fn check_always_out_bounds() {
12+
let data = kani::vec::any_vec::<u8, 8>();
13+
14+
// Capacity must match length.
15+
assert_eq!(data.capacity(), data.len());
16+
17+
// Create invalid reference.
18+
let invalid = unsafe { data.get_unchecked(data.len()) };
19+
20+
macro_rules! cover_len {
21+
($fn_name:tt, $val:literal) => {
22+
fn $fn_name(val: &u8) {
23+
cover!(*val == 0);
24+
}
25+
26+
if data.len() == $val {
27+
$fn_name(invalid);
28+
}
29+
};
30+
}
31+
32+
// Ensure any length between 0..=8 can trigger a failure.
33+
cover_len!(check_0, 0);
34+
cover_len!(check_1, 1);
35+
cover_len!(check_2, 2);
36+
cover_len!(check_3, 3);
37+
cover_len!(check_4, 4);
38+
cover_len!(check_5, 5);
39+
cover_len!(check_6, 6);
40+
cover_len!(check_7, 7);
41+
cover_len!(check_8, 8);
42+
43+
// This shouldn't be covered.
44+
cover_len!(check_9, 9);
45+
}

0 commit comments

Comments
 (0)