Skip to content

Contracts and harnesses for <*mut T>::offset_from #168

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

Merged
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 105 additions & 2 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use crate::cmp::Ordering::{Equal, Greater, Less};
use crate::intrinsics::const_eval_select;
use crate::mem::SizedTypeProperties;
use crate::slice::{self, SliceIndex};
use safety::{ensures, requires};

#[cfg(kani)]

impl<T: ?Sized> *mut T {
/// Returns `true` if the pointer is null.
Expand Down Expand Up @@ -826,11 +829,20 @@ impl<T: ?Sized> *mut T {
/// unsafe {
/// let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️
/// }
/// ```
/// ```S
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
#[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
#[inline(always)]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(
// Ensuring that subtracting 'origin' from 'self' doesnt result in an overflow
(self as isize).checked_sub(origin as isize).is_some() &&
// Ensuring that sthe distance between 'self' & 'origin' is aligned to T
(self as isize - origin as isize) % (mem::size_of::<T>() as isize) == 0 &&
// Ensuring that both pointers point to the same address or are in the same allocation
(self as isize == origin as isize || kani::mem::same_allocation(self, origin))
)]
#[ensures(|result| *result == (self as isize - origin as isize) / (mem::size_of::<T>() as isize))]
pub const unsafe fn offset_from(self, origin: *const T) -> isize
where
T: Sized,
Expand Down Expand Up @@ -2302,3 +2314,94 @@ impl<T: ?Sized> PartialOrd for *mut T {
*self >= *other
}
}

#[cfg(kani)]
#[unstable(feature = "kani", issue = "none")]
mod verify {
use crate::kani;
use kani::{PointerGenerator};
use core::mem;

// The proof for a unit type panics as offset_from needs the pointee size > 0
#[kani::proof_for_contract(<*mut ()>::offset_from)]
#[kani::should_panic]
pub fn check_mut_offset_from_unit() {
let mut val: () = ();
let src_ptr: *mut () = &mut val;
let dest_ptr: *mut () = &mut val;
unsafe {
dest_ptr.offset_from(src_ptr);
}
}

// Array size is bound for kani::any_array
const ARRAY_LEN: usize = 40;

macro_rules! generate_offset_from_harness {
($type: ty, $proof_name1: ident, $proof_name2: ident) => {
#[kani::proof_for_contract(<*mut $type>::offset_from)]
// Below function is for a single element
pub fn $proof_name1() {
const gen_size: usize = mem::size_of::<$type>();
let mut generator1 = PointerGenerator::<gen_size>::new();
let mut generator2 = PointerGenerator::<gen_size>::new();
let ptr1: *mut $type = generator1.any_in_bounds().ptr;
let ptr2: *mut $type = if kani::any() {
generator1.any_alloc_status().ptr
} else {
generator2.any_alloc_status().ptr
};

unsafe {
ptr1.offset_from(ptr2);
}


}

// Below function is for large arrays
pub fn $proof_name2() {
const gen_size: usize = mem::size_of::<$type>();
let mut generator1 = PointerGenerator::<{ gen_size * ARRAY_LEN }>::new();
let mut generator2 = PointerGenerator::<{ gen_size * ARRAY_LEN }>::new();
let ptr1: *mut $type = generator1.any_in_bounds().ptr;
let ptr2: *mut $type = if kani::any() {
generator1.any_alloc_status().ptr
} else {
generator2.any_alloc_status().ptr
};

unsafe {
ptr1.offset_from(ptr2);
}


}

};
}

generate_offset_from_harness!(u8, check_mut_offset_from_u8, check_mut_offset_from_u8_array);
generate_offset_from_harness!(u16, check_mut_offset_from_u16, check_mut_offset_from_u16_array);
generate_offset_from_harness!(u32, check_mut_offset_from_u32, check_mut_offset_from_u32_array);
generate_offset_from_harness!(u64, check_mut_offset_from_u64, check_mut_offset_from_u64_array);
generate_offset_from_harness!(u128, check_mut_offset_from_u128, check_mut_offset_from_u128_array);
generate_offset_from_harness!(usize, check_mut_offset_from_usize, check_mut_offset_from_usize_array);

generate_offset_from_harness!(i8, check_mut_offset_from_i8, check_mut_offset_from_i8_array);
generate_offset_from_harness!(i16, check_mut_offset_from_i16, check_mut_offset_from_i16_array);
generate_offset_from_harness!(i32, check_mut_offset_from_i32, check_mut_offset_from_i32_array);
generate_offset_from_harness!(i64, check_mut_offset_from_i64, check_mut_offset_from_i64_array);
generate_offset_from_harness!(i128, check_mut_offset_from_i128, check_mut_offset_from_i128_array);
generate_offset_from_harness!(isize, check_mut_offset_from_isize, check_mut_offset_from_isize_array);

generate_offset_from_harness!((i8, i8), check_mut_offset_from_tuple_1, check_mut_offset_from_tuple_1_array);
generate_offset_from_harness!((f64, bool), check_mut_offset_from_tuple_2, check_mut_offset_from_tuple_2_array);
generate_offset_from_harness!((u32, i16, f32), check_mut_offset_from_tuple_3, check_mut_offset_from_tuple_3_array);
generate_offset_from_harness!(
((), bool, u8, u16, i32, f64, i128, usize),
check_mut_offset_from_tuple_4,
check_mut_offset_from_tuple_4_array
);

}