Skip to content

Commit ff3aea3

Browse files
authored
Support concrete playback for arrays of length 65 or greater (#3888)
### Problem When CBMC generates a JSON trace for a nondeterministic array, it will output a key-value pair `elements: [array]`, where `array` contains concrete values for each element in the array. If the array is length 64 or shorter, it will _also_ output the elements of the array as separate values in the trace (so each element is in the trace twice). Prior to this PR, concrete playback relied on the latter output format to find elements of an array. However, when the array was length 65 or greater, those elements wouldn't be values in their own right, so we wouldn't find any values for the array and just output an empty array. ### Solution This PR changes our representation of concrete values to handle arrays explicitly; i.e., to look for the `elements` array and populate the concrete values of the array from that instead. ### Callouts For those wondering why the `playback_already_existed` test changed, it's because we're hashing `ConcreteItem` instead of `ConcreteValue`, so the hash changes. Resolves #3787 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 475ea5e commit ff3aea3

File tree

8 files changed

+422
-87
lines changed

8 files changed

+422
-87
lines changed

kani-driver/src/cbmc_output_parser.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,20 @@ pub struct TraceItem {
296296
/// Struct that represents a trace value.
297297
///
298298
/// Note: this struct can have a lot of different fields depending on the value type.
299-
/// The fields included right now are relevant to primitive types.
299+
/// The fields included right now are relevant to primitive types and arrays.
300300
#[derive(Clone, Debug, Deserialize)]
301301
pub struct TraceValue {
302302
pub binary: Option<String>,
303303
pub data: Option<TraceData>,
304304
pub width: Option<u32>,
305+
// Invariant: elements is Some iff binary, data, and width are None.
306+
pub elements: Option<Vec<TraceArrayValue>>,
307+
}
308+
309+
/// Struct that represents an element of an array in a trace.
310+
#[derive(Clone, Debug, Deserialize)]
311+
pub struct TraceArrayValue {
312+
pub value: TraceValue,
305313
}
306314

307315
/// Enum that represents a trace data item.

kani-driver/src/concrete_playback/test_generator.rs

+346-85
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
script: playback_target.sh
4+
expected: playback_target.expected
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Failed Checks: index out of bounds: the length is less than or equal to the given index
2+
3+
VERIFICATION:- FAILED
4+
5+
INFO: Now modifying the source code to include the concrete playback unit test:
6+
7+
running 1 test
8+
9+
index out of bounds: the len is 65 but the index is
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
# Copyright Kani Contributors
3+
# SPDX-License-Identifier: Apache-2.0 OR MIT
4+
5+
set +e
6+
7+
function check_playback {
8+
local OUTPUT=output.log
9+
cargo kani playback "${@}" >& $OUTPUT
10+
# Sort output so we can rely on the order.
11+
echo "$(grep "test verify::.* ok" $OUTPUT | sort)"
12+
echo
13+
echo "======= Raw Output ======="
14+
cat $OUTPUT
15+
echo "=========================="
16+
echo
17+
rm $OUTPUT
18+
}
19+
20+
pushd sample_crate > /dev/null
21+
cargo clean
22+
23+
cargo kani --concrete-playback inplace -Z concrete-playback
24+
check_playback -Z concrete-playback
25+
26+
cargo clean
27+
popd > /dev/null
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+
[package]
4+
name = "sample_crate"
5+
version = "0.1.0"
6+
edition = "2021"
7+
doctest = false
8+
9+
[lints.rust]
10+
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(kani)'] }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! Test that concrete playback generates concrete values for arrays over the length of 64
5+
//! and that playback can run those tests and find the index out of bounds bug,
6+
//! c.f. https://github.com/model-checking/kani/issues/3787
7+
8+
#[cfg(kani)]
9+
mod verify {
10+
#[kani::proof]
11+
fn index_array_65() {
12+
let arr: [u16; 65] = kani::any();
13+
let idx: usize = kani::any();
14+
arr[idx];
15+
}
16+
}

tests/script-based-pre/playback_already_existing/original.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ mod verify {
2525
}
2626
}
2727
#[test]
28-
fn kani_concrete_playback_try_nz_u8_17663051139329126359() {
28+
fn kani_concrete_playback_try_nz_u8_1592364891838466833() {
2929
let concrete_vals: Vec<Vec<u8>> = vec![
3030
// 0
3131
vec![0],

0 commit comments

Comments
 (0)