Skip to content

Commit 007643f

Browse files
Merge branch 'main' of https://github.com/danielhumanmod/verify-rust-std into daniel/ref_con
2 parents c9a8d9d + 20d5a0b commit 007643f

File tree

2 files changed

+94
-2
lines changed

2 files changed

+94
-2
lines changed

.github/pull_requests.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ members = [
1212
"jaisnan",
1313
"patricklam",
1414
"ranjitjhala",
15-
"carolynzech"
15+
"carolynzech",
16+
"robdockins",
17+
"HuStmpHrrr",
18+
"Eh2406"
1619
]

library/core/src/ptr/non_null.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ impl<T: ?Sized> NonNull<T> {
295295
#[must_use]
296296
#[inline]
297297
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
298+
#[ensures(|result| result.get() == self.as_ptr() as *const() as usize)]
298299
pub fn addr(self) -> NonZero<usize> {
299300
// SAFETY: The pointer is guaranteed by the type to be non-null,
300301
// meaning that the address will be non-zero.
@@ -573,6 +574,11 @@ impl<T: ?Sized> NonNull<T> {
573574
#[must_use = "returns a new pointer rather than modifying its argument"]
574575
#[stable(feature = "non_null_convenience", since = "1.80.0")]
575576
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
577+
#[requires(count.checked_mul(core::mem::size_of::<T>()).is_some()
578+
&& count * core::mem::size_of::<T>() <= isize::MAX as usize
579+
&& (self.pointer as isize).checked_add(count as isize * core::mem::size_of::<T>() as isize).is_some() // check wrapping add
580+
&& kani::mem::same_allocation(self.pointer, self.pointer.wrapping_offset(count as isize)))]
581+
#[ensures(|result: &NonNull<T>| result.as_ptr() == self.as_ptr().offset(count as isize))]
576582
pub const unsafe fn add(self, count: usize) -> Self
577583
where
578584
T: Sized,
@@ -1214,6 +1220,36 @@ impl<T: ?Sized> NonNull<T> {
12141220
#[must_use]
12151221
#[stable(feature = "non_null_convenience", since = "1.80.0")]
12161222
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
1223+
#[ensures(|result| {
1224+
// Post-condition reference: https://github.com/model-checking/verify-rust-std/pull/69/files
1225+
let stride = crate::mem::size_of::<T>();
1226+
// ZSTs
1227+
if stride == 0 {
1228+
if self.pointer.addr() % align == 0 {
1229+
return *result == 0;
1230+
} else {
1231+
return *result == usize::MAX;
1232+
}
1233+
}
1234+
// In this case, the pointer cannot be aligned
1235+
if (align % stride == 0) && (self.pointer.addr() % stride != 0) {
1236+
return *result == usize::MAX;
1237+
}
1238+
// Checking if the answer should indeed be usize::MAX when align % stride != 0
1239+
// requires computing gcd(a, stride), which is too expensive without
1240+
// quantifiers (https://model-checking.github.io/kani/rfc/rfcs/0010-quantifiers.html).
1241+
// This should be updated once quantifiers are available.
1242+
if (align % stride != 0 && *result == usize::MAX) {
1243+
return true;
1244+
}
1245+
// If we reach this case, either:
1246+
// - align % stride == 0 and self.pointer.addr() % stride == 0, so it is definitely possible to align the pointer
1247+
// - align % stride != 0 and result != usize::MAX, so align_offset is claiming that it's possible to align the pointer
1248+
// Check that applying the returned result does indeed produce an aligned address
1249+
let product = usize::wrapping_mul(*result, stride);
1250+
let new_addr = usize::wrapping_add(product, self.pointer.addr());
1251+
*result != usize::MAX && new_addr % align == 0
1252+
})]
12171253
pub const fn align_offset(self, align: usize) -> usize
12181254
where
12191255
T: Sized,
@@ -1818,6 +1854,7 @@ impl<T: ?Sized> From<&T> for NonNull<T> {
18181854
mod verify {
18191855
use super::*;
18201856
use crate::ptr::null_mut;
1857+
use kani::PointerGenerator;
18211858

18221859
// pub const unsafe fn new_unchecked(ptr: *mut T) -> Self
18231860
#[kani::proof_for_contract(NonNull::new_unchecked)]
@@ -1828,7 +1865,7 @@ mod verify {
18281865
}
18291866
}
18301867

1831-
// pub const unsafe fn new(ptr: *mut T) -> Option<Self>
1868+
// pub const fn new(ptr: *mut T) -> Option<Self>
18321869
#[kani::proof_for_contract(NonNull::new)]
18331870
pub fn non_null_check_new() {
18341871
let mut x: i32 = kani::any();
@@ -1936,4 +1973,56 @@ mod verify {
19361973
let _ = ptr.get_unchecked_mut(lower..upper);
19371974
}
19381975
}
1976+
1977+
// pub const unsafe fn add(self, count: usize) -> Self
1978+
#[kani::proof_for_contract(NonNull::add)]
1979+
pub fn non_null_check_add() {
1980+
const SIZE: usize = 100000;
1981+
let mut generator = PointerGenerator::<100000>::new();
1982+
let raw_ptr: *mut i8 = generator.any_in_bounds().ptr;
1983+
let ptr = unsafe { NonNull::new(raw_ptr).unwrap()};
1984+
// Create a non-deterministic count value
1985+
let count: usize = kani::any();
1986+
1987+
unsafe {
1988+
let result = ptr.add(count);
1989+
}
1990+
}
1991+
1992+
// pub fn addr(self) -> NonZero<usize>
1993+
#[kani::proof_for_contract(NonNull::addr)]
1994+
pub fn non_null_check_addr() {
1995+
// Create NonNull pointer & get pointer address
1996+
let x = kani::any::<usize>() as *mut i32;
1997+
let Some(nonnull_xptr) = NonNull::new(x) else { return; };
1998+
let address = nonnull_xptr.addr();
1999+
}
2000+
2001+
// pub fn align_offset(self, align: usize) -> usize
2002+
#[kani::proof_for_contract(NonNull::align_offset)]
2003+
pub fn non_null_check_align_offset() {
2004+
// Create NonNull pointer
2005+
let x = kani::any::<usize>() as *mut i32;
2006+
let Some(nonnull_xptr) = NonNull::new(x) else { return; };
2007+
2008+
// Call align_offset with valid align value
2009+
let align: usize = kani::any();
2010+
kani::assume(align.is_power_of_two());
2011+
nonnull_xptr.align_offset(align);
2012+
}
2013+
2014+
// pub fn align_offset(self, align: usize) -> usize
2015+
#[kani::should_panic]
2016+
#[kani::proof_for_contract(NonNull::align_offset)]
2017+
pub fn non_null_check_align_offset_negative() {
2018+
// Create NonNull pointer
2019+
let x = kani::any::<usize>() as *mut i8;
2020+
let Some(nonnull_xptr) = NonNull::new(x) else { return; };
2021+
2022+
// Generate align value that is not necessarily a power of two
2023+
let invalid_align: usize = kani::any();
2024+
2025+
// Trigger panic
2026+
let offset = nonnull_xptr.align_offset(invalid_align);
2027+
}
19392028
}

0 commit comments

Comments
 (0)