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

align_offset Contracts #69

Merged
merged 15 commits into from
Aug 30, 2024
63 changes: 63 additions & 0 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,20 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
///
/// Any questions go to @nagisa.
#[lang = "align_offset"]
#[safety::requires(a.is_power_of_two())]
// If T is a ZST, then answer should either be 0 or usize::MAX
#[safety::ensures(|result|
mem::size_of::<T>() != 0 || (p.addr() % a == 0 && *result == 0) || (p.addr() % a != 0 && *result == usize::MAX)
carolynzech marked this conversation as resolved.
Show resolved Hide resolved
)]
#[safety::ensures(|result| {
// If T is not a ZST and p can be aligned, then applying result as an offest should produce an aligned address
carolynzech marked this conversation as resolved.
Show resolved Hide resolved
mem::size_of::<T>() == 0 || *result == usize::MAX ||
carolynzech marked this conversation as resolved.
Show resolved Hide resolved
{
let product = usize::wrapping_mul(*result, mem::size_of::<T>());
let new_addr = usize::wrapping_add(product, p.addr());
new_addr % a == 0
}
})]
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
// 1, where the method versions of these operations are not inlined.
Expand All @@ -1901,6 +1915,8 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
///
/// Implementation of this function shall not panic. Ever.
#[inline]
#[safety::requires(m.is_power_of_two())]
#[safety::requires(x < m)]
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
carolynzech marked this conversation as resolved.
Show resolved Hide resolved
const unsafe fn mod_inv(x: usize, m: usize) -> usize {
/// Multiplicative modular inverse table modulo 2⁴ = 16.
///
Expand Down Expand Up @@ -2388,4 +2404,51 @@ mod verify {
let copy = unsafe { read_volatile(ptr) };
assert_eq!(val, copy);
}

fn check_align_offset<T>(p: *const T) {
carolynzech marked this conversation as resolved.
Show resolved Hide resolved
let a = kani::any::<usize>();
unsafe { align_offset(p, a) };
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_zst() {
let p = kani::any::<usize>() as *const ();
check_align_offset(p);
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_u8() {
let p = kani::any::<usize>() as *const u8;
check_align_offset(p);
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_u16() {
let p = kani::any::<usize>() as *const u16;
check_align_offset(p);
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_u32() {
let p = kani::any::<usize>() as *const u32;
check_align_offset(p);
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_u64() {
let p = kani::any::<usize>() as *const u64;
check_align_offset(p);
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_u128() {
let p = kani::any::<usize>() as *const u128;
check_align_offset(p);
}

#[kani::proof_for_contract(align_offset)]
fn check_align_offset_4096() {
let p = kani::any::<usize>() as *const [u128; 64];
check_align_offset(p);
}
carolynzech marked this conversation as resolved.
Show resolved Hide resolved
}
Loading