Skip to content

Commit bcdedb8

Browse files
verification for byte_add, byte_offset, and byte_offset_from
1 parent 024d84b commit bcdedb8

File tree

1 file changed

+74
-0
lines changed

1 file changed

+74
-0
lines changed

library/core/src/ptr/non_null.rs

+74
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,11 @@ impl<T: ?Sized> NonNull<T> {
502502
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
503503
#[stable(feature = "non_null_convenience", since = "1.80.0")]
504504
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
505+
#[requires(!origin.as_ptr().is_null())]
506+
#[ensures(
507+
|result: &isize|
508+
*result == (self.as_ptr() as *const u8).offset_from(origin.as_ptr() as *const u8)
509+
)]
505510
pub const unsafe fn byte_offset(self, count: isize) -> Self {
506511
// SAFETY: the caller must uphold the safety contract for `offset` and `byte_offset` has
507512
// the same safety contract.
@@ -579,6 +584,11 @@ impl<T: ?Sized> NonNull<T> {
579584
#[rustc_allow_const_fn_unstable(set_ptr_value)]
580585
#[stable(feature = "non_null_convenience", since = "1.80.0")]
581586
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
587+
#[requires(!self.as_ptr().is_null())]
588+
#[ensures(
589+
|result: &NonNull<T>|
590+
(result.as_ptr() as *const () as usize) == ((self.as_ptr() as *const () as usize) + count)
591+
)]
582592
pub const unsafe fn byte_add(self, count: usize) -> Self {
583593
// SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same
584594
// safety contract.
@@ -783,6 +793,11 @@ impl<T: ?Sized> NonNull<T> {
783793
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
784794
#[stable(feature = "non_null_convenience", since = "1.80.0")]
785795
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
796+
#[requires(!origin.as_ptr().is_null())]
797+
#[ensures(
798+
|result: &isize|
799+
*result == (self.as_ptr() as *const u8).offset_from(origin.as_ptr() as *const u8)
800+
)]
786801
pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: NonNull<U>) -> isize {
787802
// SAFETY: the caller must uphold the safety contract for `byte_offset_from`.
788803
unsafe { self.pointer.byte_offset_from(origin.pointer) }
@@ -1803,4 +1818,63 @@ mod verify {
18031818
let maybe_null_ptr = if kani::any() { xptr as *mut i32 } else { null_mut() };
18041819
let _ = NonNull::new(maybe_null_ptr);
18051820
}
1821+
1822+
#[kani::proof_for_contract(NonNull::byte_add)]
1823+
pub fn non_null_byte_add_proof() {
1824+
const ARR_SIZE: usize = 100000;
1825+
let arr: [i32; ARR_SIZE] = kani::any();
1826+
let offset = kani::any_where(|x| *x <= ARR_SIZE);
1827+
let raw_ptr: *mut i32 = arr.as_ptr() as *mut i32;
1828+
let ptr = unsafe { NonNull::new(raw_ptr.add(offset)).unwrap() };
1829+
let count: usize = kani::any();
1830+
1831+
kani::assume(count < usize::MAX);
1832+
kani::assume(count.checked_mul(mem::size_of::<i32>()).is_some());
1833+
kani::assume(count * mem::size_of::<i32>() <= (isize::MAX as usize));
1834+
kani::assume(count < ARR_SIZE - offset);
1835+
1836+
unsafe {
1837+
let result = ptr.byte_add(count);
1838+
}
1839+
}
1840+
1841+
#[kani::proof_for_contract(NonNull::byte_offset)]
1842+
pub fn non_null_byte_offset_proof() {
1843+
const ARR_SIZE: usize = 100000;
1844+
let arr: [i32; ARR_SIZE] = kani::any();
1845+
let offset = kani::any_where(|x| *x <= ARR_SIZE);
1846+
let raw_ptr: *mut i32 = arr.as_ptr() as *mut i32;
1847+
let ptr = unsafe { NonNull::new(raw_ptr.add(offset)).unwrap() };
1848+
let count: isize = kani::any();
1849+
1850+
kani::assume(count >= isize::MIN);
1851+
kani::assume(count <= isize::MAX);
1852+
kani::assume(count.checked_mul(mem::size_of::<i32>() as isize).is_some());
1853+
kani::assume(count * (mem::size_of::<i32>() as isize) <= (isize::MAX as isize));
1854+
kani::assume((offset as isize + count) < (ARR_SIZE as isize));
1855+
1856+
unsafe {
1857+
let result = ptr.byte_offset(count);
1858+
}
1859+
}
1860+
1861+
#[kani::proof_for_contract(NonNull::byte_offset_from)]
1862+
pub fn non_null_byte_offset_from_proof() {
1863+
const ARR_SIZE: usize = 100000;
1864+
let arr: [i32; ARR_SIZE] = kani::any();
1865+
1866+
// Randomly generate offsets for the pointers
1867+
let offset = kani::any_where(|x| *x < ARR_SIZE);
1868+
let origin_offset = kani::any_where(|x| *x < ARR_SIZE);
1869+
1870+
let raw_ptr: *mut i32 = arr.as_ptr() as *mut i32;
1871+
let origin_ptr: *mut i32 = arr.as_ptr() as *mut i32;
1872+
1873+
let ptr = unsafe { NonNull::new(raw_ptr.add(offset)).unwrap() };
1874+
let origin = unsafe { NonNull::new(origin_ptr.add(origin_offset)).unwrap() };
1875+
1876+
unsafe {
1877+
let result = ptr.byte_offset_from(origin);
1878+
}
1879+
}
18061880
}

0 commit comments

Comments
 (0)