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

Contracts & Harnesses for add, addr, and align_offset #105

Merged
merged 28 commits into from
Nov 14, 2024
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9c8905e
contract and harness for add
QinyuanWu Oct 2, 2024
5ea1ddc
add contract and harness to addr
QinyuanWu Oct 3, 2024
ca6813f
use can_write
QinyuanWu Oct 3, 2024
2c0dcbe
add harness for align_offset
QinyuanWu Oct 3, 2024
df2e658
minor fix
QinyuanWu Oct 3, 2024
6c341e8
minor fix
QinyuanWu Oct 3, 2024
319a002
minor fix
QinyuanWu Oct 3, 2024
64568b7
add contract and negative proof for align_offset
QinyuanWu Oct 3, 2024
2c3a17f
add comments for addr
QinyuanWu Oct 3, 2024
288abda
add requires clause for align_offset and tidy up harnesses
QinyuanWu Oct 5, 2024
404af0a
Merge branch 'model-checking:main' into dev-olivia
QinyuanWu Oct 5, 2024
c7406c1
incorporate pr suggestions
QinyuanWu Oct 21, 2024
420eb05
Merge branch 'model-checking:main' into dev-olivia
QinyuanWu Oct 21, 2024
3ec9b12
Merge branch 'dev-olivia' of https://github.com/danielhumanmod/verify…
QinyuanWu Oct 21, 2024
4e7e3a5
using same_allocation for add
QinyuanWu Oct 25, 2024
f065d6b
Merge branch 'model-checking:main' into dev-olivia
QinyuanWu Oct 28, 2024
6cfad82
misc: remove todo
QinyuanWu Oct 28, 2024
88afe64
Merge branch 'model-checking:main' into dev-olivia
QinyuanWu Oct 31, 2024
22ac1a9
address PR comments
QinyuanWu Nov 7, 2024
293a297
Merge branch 'dev-olivia' of https://github.com/danielhumanmod/verify…
QinyuanWu Nov 7, 2024
028ab6a
merge with upstream/main
QinyuanWu Nov 7, 2024
355c672
address PR comment
QinyuanWu Nov 8, 2024
b383978
revert stdarch changes
QinyuanWu Nov 12, 2024
e428231
Merge branch 'model-checking:main' into dev-olivia
QinyuanWu Nov 13, 2024
7e2eee3
simplify expressions
QinyuanWu Nov 13, 2024
dc9e9e0
use PointerGenerator for add
QinyuanWu Nov 13, 2024
25317fd
Remove unused import
carolynzech Nov 14, 2024
d26185e
Merge branch 'main' into dev-olivia
carolynzech Nov 14, 2024
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
91 changes: 90 additions & 1 deletion library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ impl<T: ?Sized> NonNull<T> {
#[must_use]
#[inline]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
#[ensures(|result| result.get() == self.as_ptr() as *const() as usize)]
pub fn addr(self) -> NonZero<usize> {
// SAFETY: The pointer is guaranteed by the type to be non-null,
// meaning that the address will be non-zero.
Expand Down Expand Up @@ -567,6 +568,11 @@ impl<T: ?Sized> NonNull<T> {
#[must_use = "returns a new pointer rather than modifying its argument"]
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
#[requires(count.checked_mul(core::mem::size_of::<T>()).is_some()
&& count * core::mem::size_of::<T>() <= isize::MAX as usize
&& (self.pointer as isize).checked_add(count as isize * core::mem::size_of::<T>() as isize).is_some() // check wrapping add
&& kani::mem::same_allocation(self.pointer, self.pointer.wrapping_offset(count as isize)))]
#[ensures(|result: &NonNull<T>| result.as_ptr() == self.as_ptr().offset(count as isize))]
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
Expand Down Expand Up @@ -1208,6 +1214,36 @@ impl<T: ?Sized> NonNull<T> {
#[must_use]
#[stable(feature = "non_null_convenience", since = "1.80.0")]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
#[ensures(|result| {
QinyuanWu marked this conversation as resolved.
Show resolved Hide resolved
// Post-condition reference: https://github.com/model-checking/verify-rust-std/pull/69/files
QinyuanWu marked this conversation as resolved.
Show resolved Hide resolved
let stride = crate::mem::size_of::<T>();
// ZSTs
if stride == 0 {
if self.pointer.addr() % align == 0 {
return *result == 0;
} else {
return *result == usize::MAX;
}
}
// In this case, the pointer cannot be aligned
if (align % stride == 0) && (self.pointer.addr() % stride != 0) {
return *result == usize::MAX;
}
// Checking if the answer should indeed be usize::MAX when align % stride != 0
// requires computing gcd(a, stride), which is too expensive without
// quantifiers (https://model-checking.github.io/kani/rfc/rfcs/0010-quantifiers.html).
// This should be updated once quantifiers are available.
if (align % stride != 0 && *result == usize::MAX) {
return true;
}
// If we reach this case, either:
// - align % stride == 0 and self.pointer.addr() % stride == 0, so it is definitely possible to align the pointer
// - align % stride != 0 and result != usize::MAX, so align_offset is claiming that it's possible to align the pointer
// Check that applying the returned result does indeed produce an aligned address
let product = usize::wrapping_mul(*result, stride);
let new_addr = usize::wrapping_add(product, self.pointer.addr());
*result != usize::MAX && new_addr % align == 0
})]
pub const fn align_offset(self, align: usize) -> usize
where
T: Sized,
Expand Down Expand Up @@ -1811,6 +1847,7 @@ impl<T: ?Sized> From<&T> for NonNull<T> {
mod verify {
use super::*;
use crate::ptr::null_mut;
use kani::PointerGenerator;

// pub const unsafe fn new_unchecked(ptr: *mut T) -> Self
#[kani::proof_for_contract(NonNull::new_unchecked)]
Expand All @@ -1821,12 +1858,64 @@ mod verify {
}
}

// pub const unsafe fn new(ptr: *mut T) -> Option<Self>
// pub const fn new(ptr: *mut T) -> Option<Self>
#[kani::proof_for_contract(NonNull::new)]
pub fn non_null_check_new() {
let mut x: i32 = kani::any();
let xptr = &mut x;
let maybe_null_ptr = if kani::any() { xptr as *mut i32 } else { null_mut() };
let _ = NonNull::new(maybe_null_ptr);
}

// pub const unsafe fn add(self, count: usize) -> Self
#[kani::proof_for_contract(NonNull::add)]
pub fn non_null_check_add() {
const SIZE: usize = 100000;
let mut generator = PointerGenerator::<100000>::new();
let raw_ptr: *mut i8 = generator.any_in_bounds().ptr;
let ptr = unsafe { NonNull::new(raw_ptr).unwrap()};
// Create a non-deterministic count value
let count: usize = kani::any();

unsafe {
let result = ptr.add(count);
}
}

// pub fn addr(self) -> NonZero<usize>
#[kani::proof_for_contract(NonNull::addr)]
pub fn non_null_check_addr() {
// Create NonNull pointer & get pointer address
let x = kani::any::<usize>() as *mut i32;
let Some(nonnull_xptr) = NonNull::new(x) else { return; };
let address = nonnull_xptr.addr();
}

// pub fn align_offset(self, align: usize) -> usize
#[kani::proof_for_contract(NonNull::align_offset)]
pub fn non_null_check_align_offset() {
// Create NonNull pointer
let x = kani::any::<usize>() as *mut i32;
let Some(nonnull_xptr) = NonNull::new(x) else { return; };

// Call align_offset with valid align value
let align: usize = kani::any();
kani::assume(align.is_power_of_two());
nonnull_xptr.align_offset(align);
}

// pub fn align_offset(self, align: usize) -> usize
#[kani::should_panic]
#[kani::proof_for_contract(NonNull::align_offset)]
pub fn non_null_check_align_offset_negative() {
// Create NonNull pointer
let x = kani::any::<usize>() as *mut i8;
let Some(nonnull_xptr) = NonNull::new(x) else { return; };

// Generate align value that is not necessarily a power of two
let invalid_align: usize = kani::any();

// Trigger panic
let offset = nonnull_xptr.align_offset(invalid_align);
}
}
Loading