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

Add harnesses for all functions in Alignment #42

Merged
merged 15 commits into from
Aug 20, 2024
Merged
Changes from all 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
85 changes: 82 additions & 3 deletions library/core/src/ptr/alignment.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use safety::requires;
use safety::{ensures, requires};
use crate::num::NonZero;
#[cfg(debug_assertions)]
use crate::ub_checks::assert_unsafe_precondition;
Expand Down Expand Up @@ -48,6 +48,8 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[requires(mem::align_of::<T>().is_power_of_two())]
#[ensures(|result| result.as_usize().is_power_of_two())]
pub const fn of<T>() -> Self {
// SAFETY: rustc ensures that type alignment is always a power of two.
unsafe { Alignment::new_unchecked(mem::align_of::<T>()) }
Expand All @@ -60,6 +62,8 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[ensures(|result| align.is_power_of_two() == result.is_some())]
#[ensures(|result| result.is_none() || result.unwrap().as_usize() == align)]
pub const fn new(align: usize) -> Option<Self> {
if align.is_power_of_two() {
// SAFETY: Just checked it only has one bit set
Expand All @@ -80,8 +84,9 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[requires(align > 0)]
#[requires((align & (align - 1)) == 0)]
#[requires(align > 0 && (align & (align - 1)) == 0)]
#[ensures(|result| result.as_usize() == align)]
#[ensures(|result| result.as_usize().is_power_of_two())]
pub const unsafe fn new_unchecked(align: usize) -> Self {
#[cfg(debug_assertions)]
assert_unsafe_precondition!(
Expand All @@ -99,6 +104,7 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[ensures(|result| result.is_power_of_two())]
pub const fn as_usize(self) -> usize {
self.0 as usize
}
Expand All @@ -107,6 +113,8 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[ensures(|result| result.get().is_power_of_two())]
#[ensures(|result| result.get() == self.as_usize())]
pub const fn as_nonzero(self) -> NonZero<usize> {
// SAFETY: All the discriminants are non-zero.
unsafe { NonZero::new_unchecked(self.as_usize()) }
Expand All @@ -128,6 +136,9 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[requires(self.as_usize().is_power_of_two())]
#[ensures(|result| (*result as usize) < mem::size_of::<usize>() * 8)]
#[ensures(|result| 1usize << *result == self.as_usize())]
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
pub const fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
}
Expand Down Expand Up @@ -158,6 +169,9 @@ impl Alignment {
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
#[ensures(|result| *result > 0)]
#[ensures(|result| *result == !(self.as_usize() -1))]
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
#[ensures(|result| self.as_usize() & *result == self.as_usize())]
pub const fn mask(self) -> usize {
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
!(unsafe { self.as_usize().unchecked_sub(1) })
Expand Down Expand Up @@ -370,3 +384,68 @@ enum AlignmentEnum {
_Align1Shl62 = 1 << 62,
_Align1Shl63 = 1 << 63,
}

#[cfg(kani)]
#[unstable(feature="kani", issue="none")]
mod verify {
use super::*;

impl kani::Arbitrary for Alignment {
fn any() -> Self {
let align = kani::any_where(|a: &usize| a.is_power_of_two());
unsafe { mem::transmute::<usize, Alignment>(align) }
}
}

// pub const fn of<T>() -> Self
#[kani::proof_for_contract(Alignment::of)]
pub fn check_of_i32() {
let _ = Alignment::of::<i32>();
}

// pub const fn new(align: usize) -> Option<Self>
#[kani::proof_for_contract(Alignment::new)]
pub fn check_new() {
let a = kani::any::<usize>();
let _ = Alignment::new(a);
}

// pub const unsafe fn new_unchecked(align: usize) -> Self
#[kani::proof_for_contract(Alignment::new_unchecked)]
pub fn check_new_unchecked() {
let a = kani::any::<usize>();
unsafe {
let _ = Alignment::new_unchecked(a);
}
}

// pub const fn as_usize(self) -> usize
#[kani::proof_for_contract(Alignment::as_usize)]
pub fn check_as_usize() {
let a = kani::any::<usize>();
if let Some(alignment) = Alignment::new(a) {
assert_eq!(alignment.as_usize(), a);
celinval marked this conversation as resolved.
Show resolved Hide resolved
}
}

// pub const fn as_nonzero(self) -> NonZero<usize>
#[kani::proof_for_contract(Alignment::as_nonzero)]
pub fn check_as_nonzero() {
let alignment = kani::any::<Alignment>();
let _ = alignment.as_nonzero();
}

// pub const fn log2(self) -> u32
#[kani::proof_for_contract(Alignment::log2)]
pub fn check_log2() {
let alignment = kani::any::<Alignment>();
let _ = alignment.log2();
}

// pub const fn mask(self) -> usize
#[kani::proof_for_contract(Alignment::mask)]
pub fn check_mask() {
let alignment = kani::any::<Alignment>();
let _ = alignment.mask();
}
}
Loading