-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Boogie Backend] Add support for int-to-int casts (#2957)
Add support for int-to-int cast operations (MIR's `Rvalue::Cast` with the `CastKind::IntToInt` kind) through implementing them as extracts/concats in Boogie. The PR also includes another unbounded verification example involving the serialization of an array of words into a buffer of bytes, which involves int-to-int cast operations. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
- Loading branch information
1 parent
8ea0e00
commit 2e57044
Showing
7 changed files
with
189 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright Kani Contributors | ||
# SPDX-License-Identifier: Apache-2.0 OR MIT | ||
script: gen_boogie_and_dump.sh | ||
expected: expected |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Datatypes: | ||
datatype $Array<T> { $Array(data: [bv64]T, len: bv64) } | ||
|
||
// Functions: | ||
function {:bvbuiltin "bvult"} $BvUnsignedLessThan<T>(lhs: T, rhs: T) returns (bool); | ||
|
||
function {:bvbuiltin "bvslt"} $BvSignedLessThan<T>(lhs: T, rhs: T) returns (bool); | ||
|
||
function {:bvbuiltin "bvugt"} $BvUnsignedGreaterThan<T>(lhs: T, rhs: T) returns (bool); | ||
|
||
function {:bvbuiltin "bvsgt"} $BvSignedGreaterThan<T>(lhs: T, rhs: T) returns (bool); | ||
|
||
function {:bvbuiltin "bvadd"} $BvAdd<T>(lhs: T, rhs: T) returns (T); | ||
|
||
function {:bvbuiltin "bvor"} $BvOr<T>(lhs: T, rhs: T) returns (T); | ||
|
||
function {:bvbuiltin "bvand"} $BvAnd<T>(lhs: T, rhs: T) returns (T); | ||
|
||
function {:bvbuiltin "bvshl"} $BvShl<T>(lhs: T, rhs: T) returns (T); | ||
|
||
function {:bvbuiltin "bvlshr"} $BvShr<T>(lhs: T, rhs: T) returns (T); | ||
|
||
// Procedures: | ||
procedure | ||
{ | ||
var src: $Array bv16; | ||
var buf: $Array bv8; | ||
var src_len: bv64; | ||
var buf_len: bv64; | ||
var i: bv64; | ||
var x: bv16; | ||
var byte0: bv8; | ||
var byte1: bv8; | ||
var j: bv64; | ||
var dst: $Array bv16; | ||
bb | ||
havoc src; | ||
goto bb | ||
havoc buf; | ||
src_len := src->len; | ||
buf_len := buf->len; | ||
:= $BvShr(buf_len, 1bv64); | ||
:= !($BvUnsignedLessThan( | ||
assume | ||
i := 0bv64; | ||
:= $BvUnsignedLessThan( | ||
if (\ | ||
goto bb\ | ||
} else { | ||
goto bb\ | ||
} | ||
havoc dst; | ||
return; | ||
:= src->data[ | ||
:= dst->data[ | ||
assert | ||
:= $BvAdd(i, 1bv64); | ||
:= $BvShl( | ||
:= buf->data[ | ||
:= (0bv8 ++ | ||
:= $BvOr( | ||
:= $BvAnd(x, 255bv16); | ||
)[8:0]; | ||
:= $BvShr(x, 8bv16); | ||
byte1 := | ||
j := $BvShl( | ||
buf->data[(j)] := byte0; | ||
:= $BvAdd(j, 1bv64); | ||
} |
13 changes: 13 additions & 0 deletions
13
tests/script-based-boogie/unbounded_array_serde/gen_boogie_and_dump.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#!/usr/bin/env bash | ||
# Copyright Kani Contributors | ||
# SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
set +e | ||
|
||
# Delete any leftover Boogie files | ||
rm *.bpl | ||
|
||
echo "[TEST] Run verification..." | ||
kani -Zboogie test.rs | ||
|
||
cat *.bpl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! A test that demonstrates unbounded verification of array-based programs. | ||
//! The test uses `any_array` which creates arrays with non-deterministic | ||
//! content and length. | ||
//! The `src` array of words is serialized into the `buf` byte array and then | ||
//! deserialized back into `dst`. | ||
//! The test checks that the round trip of serialization and deserialization is | ||
//! the identity. | ||
|
||
#[kani::proof] | ||
fn serde() { | ||
let src = kani::array::any_array::<u16>(); | ||
let mut buf = kani::array::any_array::<u8>(); | ||
let src_len: usize = src.len(); | ||
let buf_len: usize = buf.len(); | ||
kani::assume(buf_len >> 1u64 >= src_len); | ||
|
||
// serialize | ||
let mut i: usize = 0; | ||
//Loop_invariant: forall j: usize :: j < i => ((buf[j << 1u64 + 1] ++ buf[j << 1u64]) == src[j]) | ||
while i < src_len { | ||
let x = src[i]; | ||
let byte0: u8 = (x & 0xFF) as u8; | ||
let byte1: u8 = ((x >> 8u16) & 0xFF) as u8; | ||
let j: usize = i << 1u64; | ||
buf[j] = byte0; | ||
buf[j + 1] = byte1; | ||
i += 1; | ||
} | ||
|
||
// deserialize | ||
let mut dst = kani::array::any_array::<u16>(); | ||
kani::assume(dst.len() >= src_len); | ||
i = 0; | ||
//Loop_invariant: forall j: usize :: j < i => ((buf[j << 1u64 + 1] ++ buf[j << 1u64]) == dst[j]) | ||
while i < src_len { | ||
let j: usize = i << 1u64; | ||
dst[i] = ((buf[j + 1] as u16) << 8u16) | (buf[j] as u16); | ||
i += 1; | ||
} | ||
|
||
// Check the round trip | ||
i = 0; | ||
while i < src_len { | ||
kani::assert(src[i] == dst[i], "serialization/deserialization failed"); | ||
i += 1; | ||
} | ||
} |