Skip to content

Commit 07318df

Browse files
authored
Contracts and harnesses for dangling, from_raw_parts, slice_from_raw_parts, to_raw_parts in NonNull (#127)
Towards #53 Contracts and harnesses for `dangling`, `from_raw_parts`, `slice_from_raw_parts`, `to_raw_parts` in NonNull ### Discussion 1. `NonNull::slice_from_raw_parts`: [requested](model-checking/kani#3693) new Kani API to compare byte by byte 2. `NonNull::to_raw_parts`: [unstable vtable comparison 'Eq'](#139) ### Verification Result ``` SUMMARY: ** 0 of 141 failed VERIFICATION:- SUCCESSFUL Verification Time: 0.17378491s Complete - 6 successfully verified harnesses, 0 failures, 6 total. ``` 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 5e44e6e commit 07318df

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

library/core/src/ptr/non_null.rs

+130
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ impl<T: Sized> NonNull<T> {
112112
#[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")]
113113
#[must_use]
114114
#[inline]
115+
#[ensures(|result| !result.pointer.is_null() && result.pointer.is_aligned())]
115116
pub const fn dangling() -> Self {
116117
// SAFETY: ptr::dangling_mut() returns a non-null well-aligned pointer.
117118
unsafe {
@@ -269,6 +270,7 @@ impl<T: ?Sized> NonNull<T> {
269270
#[unstable(feature = "ptr_metadata", issue = "81513")]
270271
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
271272
#[inline]
273+
#[ensures(|result| !result.pointer.is_null())]
272274
pub const fn from_raw_parts(
273275
data_pointer: NonNull<()>,
274276
metadata: <T as super::Pointee>::Metadata,
@@ -287,6 +289,8 @@ impl<T: ?Sized> NonNull<T> {
287289
#[must_use = "this returns the result of the operation, \
288290
without modifying the original"]
289291
#[inline]
292+
#[ensures(|(data_ptr, metadata)| !data_ptr.as_ptr().is_null())]
293+
#[ensures(|(data_ptr, metadata)| self.as_ptr() as *const () == data_ptr.as_ptr() as *const ())]
290294
pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata) {
291295
(self.cast(), super::metadata(self.as_ptr()))
292296
}
@@ -1536,6 +1540,9 @@ impl<T> NonNull<[T]> {
15361540
#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "1.83.0")]
15371541
#[must_use]
15381542
#[inline]
1543+
#[ensures(|result| !result.pointer.is_null()
1544+
&& result.pointer as *const T == data.pointer
1545+
&& unsafe { result.as_ref() }.len() == len)]
15391546
pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
15401547
// SAFETY: `data` is a `NonNull` pointer which is necessarily non-null
15411548
unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), len)) }
@@ -1884,6 +1891,20 @@ mod verify {
18841891
use crate::ptr::null_mut;
18851892
use kani::PointerGenerator;
18861893

1894+
trait SampleTrait {
1895+
fn get_value(&self) -> i32;
1896+
}
1897+
1898+
struct SampleStruct {
1899+
value: i32,
1900+
}
1901+
1902+
impl SampleTrait for SampleStruct {
1903+
fn get_value(&self) -> i32 {
1904+
self.value
1905+
}
1906+
}
1907+
18871908
impl<T> kani::Arbitrary for NonNull<T> {
18881909
fn any() -> Self {
18891910
let ptr: *mut T = kani::any::<usize>() as *mut T;
@@ -2035,6 +2056,115 @@ mod verify {
20352056
let offset = nonnull_xptr.align_offset(invalid_align);
20362057
}
20372058

2059+
// pub const fn dangling() -> Self
2060+
#[kani::proof_for_contract(NonNull::dangling)]
2061+
pub fn non_null_check_dangling() {
2062+
// unsigned integer types
2063+
let ptr_u8 = NonNull::<u8>::dangling();
2064+
let ptr_u16 = NonNull::<u16>::dangling();
2065+
let ptr_u32 = NonNull::<u32>::dangling();
2066+
let ptr_u64 = NonNull::<u64>::dangling();
2067+
let ptr_u128 = NonNull::<u128>::dangling();
2068+
let ptr_usize = NonNull::<usize>::dangling();
2069+
// signed integer types
2070+
let ptr_i8 = NonNull::<i8>::dangling();
2071+
let ptr_i16 = NonNull::<i16>::dangling();
2072+
let ptr_i32 = NonNull::<i32>::dangling();
2073+
let ptr_i64 = NonNull::<i64>::dangling();
2074+
let ptr_i128 = NonNull::<i128>::dangling();
2075+
let ptr_isize = NonNull::<isize>::dangling();
2076+
// unit type
2077+
let ptr_unit = NonNull::<()>::dangling();
2078+
// zero length slice from dangling unit pointer
2079+
let zero_len_slice = NonNull::slice_from_raw_parts(ptr_unit, 0);
2080+
}
2081+
2082+
// pub const fn from_raw_parts(data_pointer: NonNull<()>, metadata: <T as super::Pointee>::Metadata,) -> NonNull<T>
2083+
#[kani::proof_for_contract(NonNull::from_raw_parts)]
2084+
#[kani::unwind(101)]
2085+
pub fn non_null_check_from_raw_parts() {
2086+
const ARR_LEN: usize = 100;
2087+
// Create a non-deterministic array and its slice
2088+
let arr: [i8; ARR_LEN] = kani::any();
2089+
let arr_slice = kani::slice::any_slice_of_array(&arr);
2090+
// Get a raw NonNull pointer to the start of the slice
2091+
let arr_slice_raw_ptr = NonNull::new(arr_slice.as_ptr() as *mut ()).unwrap();
2092+
// Create NonNull pointer from the start pointer and the length of the slice
2093+
let nonnull_slice = NonNull::<[i8]>::from_raw_parts(arr_slice_raw_ptr, arr_slice.len());
2094+
// Ensure slice content is preserved, runtime at this step is proportional to ARR_LEN
2095+
unsafe {
2096+
kani::assert(arr_slice == nonnull_slice.as_ref(), "slice content must be preserve");
2097+
}
2098+
2099+
// zero-length dangling pointer example
2100+
let dangling_ptr = NonNull::<()>::dangling();
2101+
let zero_length = NonNull::<[()]>::from_raw_parts(dangling_ptr, 0);
2102+
}
2103+
2104+
#[kani::proof_for_contract(NonNull::from_raw_parts)]
2105+
pub fn non_null_check_from_raw_part_trait() {
2106+
// Create a SampleTrait object from SampleStruct
2107+
let sample_struct = SampleStruct { value: kani::any() };
2108+
let trait_object: &dyn SampleTrait = &sample_struct;
2109+
2110+
// Get the raw data pointer and metadata for the trait object
2111+
let trait_ptr = NonNull::new(trait_object as *const dyn SampleTrait as *mut ()).unwrap();
2112+
// Safety: For trait objects, the metadata must come from a pointer to the same underlying erased type
2113+
let metadata = core::ptr::metadata(trait_object);
2114+
2115+
// Create NonNull<dyn MyTrait> from the data pointer and metadata
2116+
let nonnull_trait_object: NonNull<dyn SampleTrait> = NonNull::from_raw_parts(trait_ptr, metadata);
2117+
2118+
unsafe {
2119+
// Ensure trait method and member is preserved
2120+
kani::assert( trait_object.get_value() == nonnull_trait_object.as_ref().get_value(), "trait method and member must correctly preserve");
2121+
}
2122+
}
2123+
2124+
// pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self
2125+
#[kani::proof_for_contract(NonNull::slice_from_raw_parts)]
2126+
#[kani::unwind(1001)]
2127+
pub fn non_null_check_slice_from_raw_parts() {
2128+
const ARR_LEN: usize = 1000;
2129+
// Create a non-deterministic array
2130+
let mut arr: [i8; ARR_LEN] = kani::any();
2131+
// Get a raw NonNull pointer to the start of the slice
2132+
let arr_raw_ptr = NonNull::new(arr.as_mut_ptr()).unwrap();
2133+
// Create NonNull slice from the start pointer and ends at random slice_len
2134+
// Safety: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
2135+
let slice_len: usize = kani::any();
2136+
kani::assume(slice_len <= ARR_LEN);
2137+
let nonnull_slice = NonNull::<[i8]>::slice_from_raw_parts(arr_raw_ptr, slice_len);
2138+
// Ensure slice content is preserved, runtime at this step is proportional to ARR_LEN
2139+
unsafe {
2140+
kani::assert(&arr[..slice_len] == nonnull_slice.as_ref(), "slice content must be preserve");
2141+
}
2142+
2143+
// TODO: zero-length example blocked by kani issue [#3670](https://github.com/model-checking/kani/issues/3670)
2144+
//let dangling_ptr = NonNull::<()>::dangling();
2145+
//let zero_length = NonNull::<[()]>::slice_from_raw_parts(dangling_ptr, 0);
2146+
}
2147+
2148+
2149+
// pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata)
2150+
#[kani::proof_for_contract(NonNull::to_raw_parts)]
2151+
pub fn non_null_check_to_raw_parts() {
2152+
// Create a SampleTrait object from SampleStruct
2153+
let sample_struct = SampleStruct { value: kani::any() };
2154+
let trait_object: &dyn SampleTrait = &sample_struct;
2155+
2156+
// Get the raw data pointer and metadata for the trait object
2157+
let trait_ptr = NonNull::from(trait_object).cast::<()>(); //both have eq failure
2158+
//let trait_ptr = NonNull::new(trait_object as *const dyn SampleTrait as *mut ()).unwrap(); //Question: what's the difference
2159+
// Safety: For trait objects, the metadata must come from a pointer to the same underlying erased type
2160+
let metadata = core::ptr::metadata(trait_object);
2161+
2162+
// Create NonNull<dyn MyTrait> from the data pointer and metadata
2163+
let nonnull_trait_object: NonNull<dyn SampleTrait> = NonNull::from_raw_parts(trait_ptr, metadata);
2164+
let (decomposed_data_ptr, decomposed_metadata) = NonNull::to_raw_parts(nonnull_trait_object);
2165+
}
2166+
2167+
20382168
#[kani::proof_for_contract(NonNull::as_mut)]
20392169
pub fn non_null_check_as_mut() {
20402170
let mut x: i32 = kani::any();

0 commit comments

Comments
 (0)