Skip to content

Commit 3612e5c

Browse files
QinyuanWuOwOzhassan-aws
authored
Contracts & Harnesses for non_null::new and non_null::new_unchecked (model-checking#88)
Towards model-checking#53 ### Changes - added contract and harness for `non_null::new` - added contract and harness for `non_null::new_unchecked` The difference between the two APIs is that `non_null::new` can handle null pointers while `non_null::new_unchecked` does not. Therefore the contract for `non_null::new` does not require a `nonnull` pointer. ### Re-validation To re-validate the verification results, run `kani verify-std -Z unstable-options "path/to/library" -Z function-contracts -Z mem-predicates --harness ptr::non_null::verify::non_null_check_new`. This will run both harnesses. All default checks should pass. --------- Co-authored-by: OwO <[email protected]> Co-authored-by: Zyad Hassan <[email protected]>
1 parent 22d39e0 commit 3612e5c

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

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)