Skip to content

Commit af6942e

Browse files
authored
Merge branch 'c-0011-core-nums-yenyunw-unsafe-ints' into c-0011-core-nums-rajathm-unsafe-ints
2 parents ae678de + 54a03ef commit af6942e

File tree

4 files changed

+101
-23
lines changed

4 files changed

+101
-23
lines changed

doc/src/tools/kani.md

+59-18
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Kani is designed to prove safety properties in your code as well as
55
the absence of some forms of undefined behavior. It uses model checking under the hood to ensure that
66
Rust programs adhere to user specified properties.
77

8-
You can find more information about how to install in [this section of the Kani book](https://model-checking.github.io/kani/install-guide.html).
8+
You can find more information about how to install in [the installation section of the Kani book](https://model-checking.github.io/kani/install-guide.html).
99

1010
## Usage
1111

@@ -27,7 +27,8 @@ fn harness() {
2727
let a = kani::any::<i32>();
2828
let b = kani::any::<i32>();
2929
let result = abs_diff(a, b);
30-
kani::assert(result >= 0, "Result should always be more than 0");}
30+
kani::assert(result >= 0, "Result should always be more than 0");
31+
}
3132
```
3233

3334
Running the command `cargo kani` in your cargo crate will give the result
@@ -46,29 +47,28 @@ Verification failed for - harness
4647
Complete - 0 successfully verified harnesses, 1 failures, 1 total.
4748
```
4849

50+
For a more detailed tutorial, you can refer to the [tutorial section of the Kani book](https://model-checking.github.io/kani/kani-tutorial.html).
4951

5052
## Using Kani to verify the Rust Standard Library
5153

52-
To aid the Rust Standard Library verification effort, Kani provides a sub-command out of the box to help you get started.
54+
Here is a short tutorial of how to use Kani to verify proofs for the standard library.
5355

54-
### Step 1
56+
### Step 1 - Add some proofs to your copy of the model-checking std
5557

56-
Modify your local copy of the Rust Standard Library by writing proofs for the functions/methods that you want to verify.
58+
Create a local copy of the [model-checking fork](https://github.com/model-checking/verify-rust-std) of the Rust Standard Library. The fork comes with Kani configured, so all you'll need to do is to call Kani's building-block APIs (such as
59+
`assert`, `assume`, `proof` and [function-contracts](https://github.com/model-checking/kani/blob/main/rfc/src/rfcs/0009-function-contracts.md) such as `modifies`, `requires` and `ensures`) directly.
5760

58-
For example, insert this short blob into your copy of the library. This blob imports the building-block APIs such as
59-
`assert`, `assume`, `proof` and [function-contracts](https://github.com/model-checking/kani/blob/main/rfc/src/rfcs/0009-function-contracts.md) such as `proof_for_contract` and `fake_function`.
6061

61-
``` rust
62-
#[cfg(kani)]
63-
kani_core::kani_lib!(core);
62+
For example, insert this module into an existing file in the core library, like `library/core/src/hint.rs` or `library/core/src/error.rs` in your copy of the library. This is just for the purpose of getting started, so you can insert in any existing file in the core library if you have other preferences.
6463

64+
``` rust
6565
#[cfg(kani)]
6666
#[unstable(feature = "kani", issue = "none")]
6767
pub mod verify {
6868
use crate::kani;
6969

7070
#[kani::proof]
71-
pub fn harness() {
71+
pub fn harness_introduction() {
7272
kani::assert(true, "yay");
7373
}
7474

@@ -84,21 +84,24 @@ pub mod verify {
8484
}
8585
```
8686

87-
### Step 2
87+
### Step 2 - Run the Kani verify-std subcommand
8888

89-
Run the following command in your local terminal:
89+
To aid the Rust Standard Library verification effort, Kani provides a sub-command out of the box to help you get started.
90+
Run the following command in your local terminal (Replace "/path/to/library" and "/path/to/target" with your local paths) from the verify repository root:
9091

91-
`kani verify-std -Z unstable-options "path/to/library" --target-dir "/path/to/target" -Z function-contracts -Z stubbing`.
92+
```
93+
kani verify-std -Z unstable-options "/path/to/library" --target-dir "/path/to/target" -Z function-contracts -Z mem-predicates
94+
```
9295

9396
The command `kani verify-std` is a sub-command of the `kani`. This specific sub-command is used to verify the Rust Standard Library with the following arguments.
9497

95-
- `"path/to/library"`: This argument specifies the path to the modified Rust Standard Library that was prepared earlier in the script.
96-
- `--target-dir "path/to/target"`: This optional argument sets the target directory where Kani will store its output and intermediate files.
98+
- `"path/to/library"`: This argument specifies the path to the modified Rust Standard Library that was prepared earlier in the script. For example, `./library` or `/home/ubuntu/verify-rust-std/library`
99+
- `--target-dir "path/to/target"`: This optional argument sets the target directory where Kani will store its output and intermediate files. For example, `/tmp` or `/tmp/verify-std`
97100

98-
Apart from these, you can use your regular `kani-args` such as `-Z function-contracts` and `-Z stubbing` depending on your verification needs.
101+
Apart from these, you can use your regular `kani-args` such as `-Z function-contracts`, `-Z stubbing` and `-Z mem-predicates` depending on your verification needs. If you run into a Kani error that says `Use of unstable feature`, add the corresponding feature with `-Z` to the command line.
99102
For more details on Kani's features, refer to [the features section in the Kani Book](https://model-checking.github.io/kani/reference/attributes.html)
100103

101-
### Step 3
104+
### Step 3 - Check verification result
102105

103106
After running the command, you can expect an output that looks like this:
104107

@@ -112,6 +115,44 @@ Verification Time: 0.017101772s
112115
Complete - 2 successfully verified harnesses, 0 failures, 2 total.
113116
```
114117

118+
### Running on a specific harness
119+
120+
You can specify a specific harness to be verified using the `--harness` flag.
121+
122+
For example, in your local copy of the verify repo, run the following command.
123+
124+
```
125+
kani verify-std --harness harness_introduction -Z unstable-options "./library" --target-dir "/tmp" -Z function-contracts -Z mem-predicates
126+
```
127+
128+
This gives you the verification result for just `harness_introduction` from the aforementioned blob.
129+
130+
```
131+
RESULTS:
132+
Check 1: verify::harness_introduction.assertion.1
133+
- Status: SUCCESS
134+
- Description: "yay"
135+
- Location: library/core/src/lib.rs:479:9 in function verify::harness_introduction
136+
137+
138+
SUMMARY:
139+
** 0 of 1 failed
140+
141+
VERIFICATION:- SUCCESSFUL
142+
Verification Time: 0.01885804s
143+
144+
Complete - 1 successfully verified harnesses, 0 failures, 1 total.
145+
```
146+
147+
Now you can write proof harnesses to verify specific functions in the library.
148+
The current convention is to keep proofs in the same module file of the verification target.
149+
To run Kani for an individual proof, use `--harness [harness_function_name]`.
150+
Note that Kani will batch run all proofs in the library folder if you do not supply the `--harness` flag.
151+
If Kani returns the error `no harnesses matched the harness filter`, you can give the full name of the harness.
152+
For example, to run the proof harness named `check_new` in `library/core/src/ptr/unique.rs`, use
153+
`--harness ptr::unique::verify::check_new`. To run all proofs in `unique.rs`, use `--harness ptr::unique::verify`.
154+
To find the full name of a harness, check the Kani output and find the line starting with `Checking harness [harness full name]`.
155+
115156
## More details
116157

117158
You can find more information about how to install and how you can customize your use of Kani in the

library/core/src/num/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1692,8 +1692,6 @@ mod verify {
16921692
generate_unchecked_mul_harness!(i64, unchecked_mul, checked_unchecked_mul_i64, -1_000i64, 1_000i64);
16931693
generate_unchecked_mul_harness!(i128, unchecked_mul, checked_unchecked_mul_i128, -1_000_000_000_000_000i128, 1_000_000_000_000_000i128);
16941694
generate_unchecked_mul_harness!(isize, unchecked_mul, checked_unchecked_mul_isize, -100_000isize, 100_000isize);
1695-
1696-
16971695
generate_unchecked_math_harness!(u8, unchecked_mul, checked_unchecked_mul_u8);
16981696
generate_unchecked_math_harness!(u16, unchecked_mul, checked_unchecked_mul_u16);
16991697
generate_unchecked_mul_harness!(u32, unchecked_mul, checked_unchecked_mul_u32, 0u32, 20_000u32);
@@ -1724,5 +1722,6 @@ mod verify {
17241722
generate_unchecked_shift_harness!(u64, unchecked_shr, checked_unchecked_shr_u64);
17251723
generate_unchecked_shift_harness!(u128, unchecked_shr, checked_unchecked_shr_u128);
17261724
generate_unchecked_shift_harness!(usize, unchecked_shr, checked_unchecked_shr_usize);
1727-
1725+
}
1726+
}
17281727
}

library/core/src/ptr/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2552,8 +2552,12 @@ mod verify {
25522552
}
25532553

25542554
#[kani::proof_for_contract(align_offset)]
2555-
fn check_align_offset_17() {
2556-
let p = kani::any::<usize>() as *const [char; 17];
2555+
// The purpose of this harness is to test align_offset with a pointee type whose stride is not a power of two
2556+
// Keeping the size smaller (5) and changing the solver to kissat improves verification time
2557+
// c.f. https://github.com/model-checking/verify-rust-std/pull/89
2558+
#[kani::solver(kissat)]
2559+
fn check_align_offset_5() {
2560+
let p = kani::any::<usize>() as *const [char; 5];
25572561
check_align_offset(p);
25582562
}
25592563

library/core/src/ptr/non_null.rs

+34
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ use crate::ptr::Unique;
88
use crate::slice::{self, SliceIndex};
99
use crate::ub_checks::assert_unsafe_precondition;
1010
use crate::{fmt, hash, intrinsics, ptr};
11+
use safety::{ensures, requires};
12+
13+
14+
#[cfg(kani)]
15+
use crate::kani;
1116

1217
/// `*mut T` but non-zero and [covariant].
1318
///
@@ -192,6 +197,8 @@ impl<T: ?Sized> NonNull<T> {
192197
#[stable(feature = "nonnull", since = "1.25.0")]
193198
#[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.25.0")]
194199
#[inline]
200+
#[requires(!ptr.is_null())]
201+
#[ensures(|result| result.as_ptr() == ptr)]
195202
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
196203
// SAFETY: the caller must guarantee that `ptr` is non-null.
197204
unsafe {
@@ -221,6 +228,8 @@ impl<T: ?Sized> NonNull<T> {
221228
#[stable(feature = "nonnull", since = "1.25.0")]
222229
#[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")]
223230
#[inline]
231+
#[ensures(|result| result.is_some() == !ptr.is_null())]
232+
#[ensures(|result| result.is_none() || result.expect("ptr is null!").as_ptr() == ptr)]
224233
pub const fn new(ptr: *mut T) -> Option<Self> {
225234
if !ptr.is_null() {
226235
// SAFETY: The pointer is already checked and is not null
@@ -1770,3 +1779,28 @@ impl<T: ?Sized> From<&T> for NonNull<T> {
17701779
unsafe { NonNull { pointer: reference as *const T } }
17711780
}
17721781
}
1782+
1783+
#[cfg(kani)]
1784+
#[unstable(feature="kani", issue="none")]
1785+
mod verify {
1786+
use super::*;
1787+
use crate::ptr::null_mut;
1788+
1789+
// pub const unsafe fn new_unchecked(ptr: *mut T) -> Self
1790+
#[kani::proof_for_contract(NonNull::new_unchecked)]
1791+
pub fn non_null_check_new_unchecked() {
1792+
let raw_ptr = kani::any::<usize>() as *mut i32;
1793+
unsafe {
1794+
let _ = NonNull::new_unchecked(raw_ptr);
1795+
}
1796+
}
1797+
1798+
// pub const unsafe fn new(ptr: *mut T) -> Option<Self>
1799+
#[kani::proof_for_contract(NonNull::new)]
1800+
pub fn non_null_check_new() {
1801+
let mut x: i32 = kani::any();
1802+
let xptr = &mut x;
1803+
let maybe_null_ptr = if kani::any() { xptr as *mut i32 } else { null_mut() };
1804+
let _ = NonNull::new(maybe_null_ptr);
1805+
}
1806+
}

0 commit comments

Comments
 (0)