Skip to content

Commit a8a28ee

Browse files
celinvalfeliperodrizhassan-awscarolynzech
authored
Add regular & fixme tests for function contracts (#3371)
I'm adding a few fix-me tests that I bumped into while working on #3363. Most of them will be fixed by #3363, except the one related to #3370. The original PR is already quite large, so I decided to just push all of these as fixme tests for now. This is now ready for review! By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: Felipe R. Monteiro <felisous@amazon.com> Co-authored-by: Zyad Hassan <88045115+zhassan-aws@users.noreply.github.com> Co-authored-by: Carolyn Zech <cmzech@amazon.com>
1 parent 5047ffb commit a8a28ee

File tree

3 files changed

+172
-4
lines changed

3 files changed

+172
-4
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//! Checks that function contracts work with different types of receivers. I.e.:
4+
//! - &Self (i.e. &self)
5+
//! - &mut Self (i.e &mut self)
6+
//! - Box<Self>
7+
//! - Rc<Self>
8+
//! - Arc<Self>
9+
//! - Pin<P> where P is one of the types above
10+
//! Source: <https://doc.rust-lang.org/reference/items/traits.html?highlight=receiver#object-safety>
11+
// compile-flags: --edition 2021
12+
// kani-flags: -Zfunction-contracts
13+
14+
#![feature(rustc_attrs)]
15+
16+
extern crate kani;
17+
18+
use std::boxed::Box;
19+
use std::pin::Pin;
20+
use std::rc::Rc;
21+
use std::sync::Arc;
22+
23+
/// Type representing a valid ASCII value going from `0..128`.
24+
#[derive(Copy, Clone, PartialEq, Eq)]
25+
#[rustc_layout_scalar_valid_range_start(0)]
26+
#[rustc_layout_scalar_valid_range_end(128)]
27+
struct CharASCII(u8);
28+
29+
impl kani::Arbitrary for CharASCII {
30+
fn any() -> CharASCII {
31+
let val = kani::any_where(|inner: &u8| *inner < 128);
32+
unsafe { CharASCII(val) }
33+
}
34+
}
35+
36+
/// This type contains unsafe setter functions with the same contract but different type of
37+
/// receivers.
38+
impl CharASCII {
39+
#[kani::modifies(&self.0)]
40+
#[kani::requires(new_val < 128)]
41+
#[kani::ensures(|_| self.0 == new_val)]
42+
unsafe fn set_val(&mut self, new_val: u8) {
43+
self.0 = new_val
44+
}
45+
46+
#[kani::modifies(&self.0)]
47+
#[kani::requires(new_val < 128)]
48+
#[kani::ensures(|_| self.0 == new_val)]
49+
unsafe fn set_mut_ref(self: &mut Self, new_val: u8) {
50+
self.0 = new_val
51+
}
52+
53+
#[kani::modifies(&self.as_ref().0)]
54+
#[kani::requires(new_val < 128)]
55+
#[kani::ensures(|_| self.as_ref().0 == new_val)]
56+
unsafe fn set_box(mut self: Box<Self>, new_val: u8) {
57+
self.as_mut().0 = new_val
58+
}
59+
60+
#[kani::modifies(&self.as_ref().0)]
61+
#[kani::requires(new_val < 128)]
62+
#[kani::ensures(|_| self.as_ref().0 == new_val)]
63+
unsafe fn set_rc(mut self: Rc<Self>, new_val: u8) {
64+
Rc::<_>::get_mut(&mut self).unwrap().0 = new_val
65+
}
66+
67+
#[kani::modifies(&self.as_ref().0)]
68+
#[kani::requires(new_val < 128)]
69+
#[kani::ensures(|_| self.as_ref().0 == new_val)]
70+
unsafe fn set_arc(mut self: Arc<Self>, new_val: u8) {
71+
Arc::<_>::get_mut(&mut self).unwrap().0 = new_val;
72+
}
73+
74+
#[kani::modifies(&self.0)]
75+
#[kani::requires(new_val < 128)]
76+
#[kani::ensures(|_| self.0 == new_val)]
77+
unsafe fn set_pin(mut self: Pin<&mut Self>, new_val: u8) {
78+
self.0 = new_val
79+
}
80+
81+
#[kani::modifies(&self.0)]
82+
#[kani::requires(new_val < 128)]
83+
#[kani::ensures(|_| self.0 == new_val)]
84+
unsafe fn set_pin_box(mut self: Pin<Box<Self>>, new_val: u8) {
85+
self.0 = new_val
86+
}
87+
}
88+
89+
mod verify {
90+
use super::*;
91+
use kani::Arbitrary;
92+
93+
#[kani::proof_for_contract(CharASCII::set_val)]
94+
fn check_set_val() {
95+
let mut obj = CharASCII::any();
96+
let original = obj.0;
97+
let new_val: u8 = kani::any();
98+
unsafe { obj.set_val(new_val) };
99+
}
100+
101+
#[kani::proof_for_contract(CharASCII::set_mut_ref)]
102+
fn check_mut_ref() {
103+
let mut obj = CharASCII::any();
104+
let new_val: u8 = kani::any();
105+
unsafe { obj.set_mut_ref(new_val) };
106+
}
107+
108+
#[kani::proof_for_contract(CharASCII::set_box)]
109+
fn check_box() {
110+
let obj = CharASCII::any();
111+
let original = obj.0;
112+
let new_val: u8 = kani::any();
113+
unsafe { Box::new(obj).set_box(new_val) };
114+
}
115+
116+
#[kani::proof_for_contract(CharASCII::set_rc)]
117+
fn check_rc() {
118+
let obj = CharASCII::any();
119+
let original = obj.0;
120+
let new_val: u8 = kani::any();
121+
unsafe { Rc::new(obj).set_rc(new_val) };
122+
}
123+
124+
#[kani::proof_for_contract(CharASCII::set_arc)]
125+
fn check_arc() {
126+
let obj = CharASCII::any();
127+
let original = obj.0;
128+
let new_val: u8 = kani::any();
129+
unsafe { Arc::new(obj).set_arc(new_val) };
130+
}
131+
132+
#[kani::proof_for_contract(CharASCII::set_pin)]
133+
fn check_pin() {
134+
let mut obj = CharASCII::any();
135+
let original = obj.0;
136+
let new_val: u8 = kani::any();
137+
unsafe { Pin::new(&mut obj).set_pin(new_val) };
138+
}
139+
140+
#[kani::proof_for_contract(CharASCII::set_pin_box)]
141+
fn check_pin_box() {
142+
let obj = CharASCII::any();
143+
let original = obj.0;
144+
let new_val: u8 = kani::any();
145+
unsafe { Pin::new(Box::new(obj)).set_pin_box(new_val) };
146+
}
147+
}

tests/kani/FunctionContracts/fn_params.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ struct MyStruct {
2121
#[kani::requires(val.u == tup_u)]
2222
#[kani::requires(Ok(val.c) == char::try_from(first))]
2323
#[kani::requires(val.c == tup_c)]
24-
/// We need this extra clause due to <https://github.com/model-checking/kani/issues/3370>.
25-
#[kani::requires(char::try_from(first).is_ok())]
2624
pub fn odd_parameters_eq(
2725
[first, second]: [u32; 2],
2826
(tup_c, tup_u): (char, u32),
@@ -41,8 +39,6 @@ pub fn odd_parameters_eq(
4139
#[kani::requires(val.u == tup_u)]
4240
#[kani::requires(Ok(val.c) == char::try_from(first))]
4341
// MISSING: #[kani::requires(val.c == tup_c)]
44-
// We need this extra clause due to <https://github.com/model-checking/kani/issues/3370>.
45-
#[kani::requires(char::try_from(first).is_ok())]
4642
pub fn odd_parameters_eq_wrong(
4743
[first, second]: [u32; 2],
4844
(tup_c, tup_u): (char, u32),
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+
//! Check that Kani correctly verifies the contract that modifies slices.
4+
//!
5+
//! Note that this test used to crash while parsing the annotations.
6+
// kani-flags: -Zfunction-contracts
7+
extern crate kani;
8+
9+
#[kani::requires(idx < slice.len())]
10+
#[kani::modifies(slice.as_ptr().wrapping_add(idx))]
11+
#[kani::ensures(|_| slice[idx] == new_val)]
12+
fn modify_slice(slice: &mut [u32], idx: usize, new_val: u32) {
13+
*slice.get_mut(idx).unwrap() = new_val;
14+
}
15+
16+
#[cfg(kani)]
17+
mod verify {
18+
use super::modify_slice;
19+
20+
#[kani::proof_for_contract(modify_slice)]
21+
fn check_modify_slice() {
22+
let mut data = kani::vec::any_vec::<u32, 5>();
23+
modify_slice(&mut data, kani::any(), kani::any())
24+
}
25+
}

0 commit comments

Comments
 (0)