Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contract and harness for as_ptr, cast, as_mut_ptr, and as_non_null_ptr #126

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
52 changes: 52 additions & 0 deletions library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ impl<T: ?Sized> NonNull<T> {
#[rustc_never_returns_null_ptr]
#[must_use]
#[inline(always)]
//Ensures address of resulting pointer is same as original
#[ensures(|result: &*mut T| *result == self.pointer as *mut T)]
pub const fn as_ptr(self) -> *mut T {
self.pointer as *mut T
}
Expand Down Expand Up @@ -430,6 +432,10 @@ impl<T: ?Sized> NonNull<T> {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
// Address preservation
#[ensures(|result: &NonNull<U>| result.as_ptr() as *const () as usize == self.as_ptr() as *const () as usize )]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use addr() instead wherever you are casting to usize.

// Ensures pointer is properly aligned for new type 'U'
#[ensures(|result: &NonNull<U>| (self.as_ptr() as *const () as usize) % core::mem::align_of::<U>() == 0)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't assume that. NonNull pointers can be unaligned.

pub const fn cast<U>(self) -> NonNull<U> {
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
Expand Down Expand Up @@ -1508,6 +1514,8 @@ impl<T> NonNull<[T]> {
#[must_use]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
// Address preservation
#[ensures(|result: &NonNull<T>| result.as_ptr() as *const () as usize == self.pointer as *const () as usize)]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.cast()
}
Expand All @@ -1528,6 +1536,8 @@ impl<T> NonNull<[T]> {
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_never_returns_null_ptr]
// Address preservation
#[ensures(|result: &*mut T| *result == self.pointer as *mut T)]
pub const fn as_mut_ptr(self) -> *mut T {
self.as_non_null_ptr().as_ptr()
}
Expand Down Expand Up @@ -1803,4 +1813,46 @@ mod verify {
let maybe_null_ptr = if kani::any() { xptr as *mut i32 } else { null_mut() };
let _ = NonNull::new(maybe_null_ptr);
}

#[kani::proof_for_contract(NonNull::as_ptr)]
pub fn non_null_check_as_ptr() {
Dhvani-Kapadia marked this conversation as resolved.
Show resolved Hide resolved
// Create a non-null pointer to a random value
let non_null_ptr: *mut i32 = kani::any::<usize>() as *mut i32;
if let Some(ptr) = NonNull::new(non_null_ptr){
// Call as_ptr
let raw_ptr = ptr.as_ptr();}

}
#[kani::proof_for_contract(NonNull::<[T]>::as_mut_ptr)]
pub fn non_null_check_as_mut_ptr() {
// Create a non-null slice pointer
const ARR_LEN: usize = 100;
let mut generator = kani::PointerGenerator::<ARR_LEN>::new();
let mut values: [i32; ARR_LEN] = [0; ARR_LEN];
let raw_ptr: *mut i32 = generator.any_in_bounds().ptr;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use any_alloc_status() instead. Or the arbitrary implementation from #128

if let Some(ptr) = NonNull::new(raw_ptr){
let slice_ptr = NonNull::slice_from_raw_parts(ptr, values.len());
// Call as_mut_ptr
let raw_ptr = slice_ptr.as_mut_ptr();
}}
#[kani::proof_for_contract(NonNull::<T>::cast)]
pub fn non_null_check_cast() {
// Create a non-null pointer to a random value
let non_null_ptr: *mut i32 = kani::any::<usize>() as *mut i32;
if let Some(ptr) = NonNull::new(non_null_ptr){
// Perform the cast
let casted_ptr: NonNull<u8> = ptr.cast();
}}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please fix indentation?

#[kani::proof_for_contract(NonNull::<[T]>::as_non_null_ptr)]
pub fn non_null_check_as_non_null_ptr() {
const ARR_LEN: usize = 100;
let mut generator = kani::PointerGenerator::<ARR_LEN>::new();
let mut values: [i32; ARR_LEN] = [0; ARR_LEN];
let raw_ptr: *mut i32 = generator.any_in_bounds().ptr;
if let Some(ptr) = NonNull::new(raw_ptr){
let slice_ptr = NonNull::slice_from_raw_parts(ptr, values.len());
let result = slice_ptr.as_non_null_ptr();
}}

}