Skip to content

Commit 03c735b

Browse files
authored
Add harnesses for all functions in Alignment (rust-lang#42)
1 parent c155b26 commit 03c735b

File tree

1 file changed

+82
-3
lines changed

1 file changed

+82
-3
lines changed

library/core/src/ptr/alignment.rs

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use safety::requires;
1+
use safety::{ensures, requires};
22
use crate::num::NonZero;
33
#[cfg(debug_assertions)]
44
use crate::ub_checks::assert_unsafe_precondition;
@@ -48,6 +48,8 @@ impl Alignment {
4848
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
4949
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
5050
#[inline]
51+
#[requires(mem::align_of::<T>().is_power_of_two())]
52+
#[ensures(|result| result.as_usize().is_power_of_two())]
5153
pub const fn of<T>() -> Self {
5254
// SAFETY: rustc ensures that type alignment is always a power of two.
5355
unsafe { Alignment::new_unchecked(mem::align_of::<T>()) }
@@ -60,6 +62,8 @@ impl Alignment {
6062
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
6163
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
6264
#[inline]
65+
#[ensures(|result| align.is_power_of_two() == result.is_some())]
66+
#[ensures(|result| result.is_none() || result.unwrap().as_usize() == align)]
6367
pub const fn new(align: usize) -> Option<Self> {
6468
if align.is_power_of_two() {
6569
// SAFETY: Just checked it only has one bit set
@@ -80,8 +84,9 @@ impl Alignment {
8084
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
8185
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
8286
#[inline]
83-
#[requires(align > 0)]
84-
#[requires((align & (align - 1)) == 0)]
87+
#[requires(align > 0 && (align & (align - 1)) == 0)]
88+
#[ensures(|result| result.as_usize() == align)]
89+
#[ensures(|result| result.as_usize().is_power_of_two())]
8590
pub const unsafe fn new_unchecked(align: usize) -> Self {
8691
#[cfg(debug_assertions)]
8792
assert_unsafe_precondition!(
@@ -99,6 +104,7 @@ impl Alignment {
99104
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
100105
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
101106
#[inline]
107+
#[ensures(|result| result.is_power_of_two())]
102108
pub const fn as_usize(self) -> usize {
103109
self.0 as usize
104110
}
@@ -107,6 +113,8 @@ impl Alignment {
107113
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
108114
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
109115
#[inline]
116+
#[ensures(|result| result.get().is_power_of_two())]
117+
#[ensures(|result| result.get() == self.as_usize())]
110118
pub const fn as_nonzero(self) -> NonZero<usize> {
111119
// SAFETY: All the discriminants are non-zero.
112120
unsafe { NonZero::new_unchecked(self.as_usize()) }
@@ -128,6 +136,9 @@ impl Alignment {
128136
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
129137
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
130138
#[inline]
139+
#[requires(self.as_usize().is_power_of_two())]
140+
#[ensures(|result| (*result as usize) < mem::size_of::<usize>() * 8)]
141+
#[ensures(|result| 1usize << *result == self.as_usize())]
131142
pub const fn log2(self) -> u32 {
132143
self.as_nonzero().trailing_zeros()
133144
}
@@ -158,6 +169,9 @@ impl Alignment {
158169
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
159170
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
160171
#[inline]
172+
#[ensures(|result| *result > 0)]
173+
#[ensures(|result| *result == !(self.as_usize() -1))]
174+
#[ensures(|result| self.as_usize() & *result == self.as_usize())]
161175
pub const fn mask(self) -> usize {
162176
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
163177
!(unsafe { self.as_usize().unchecked_sub(1) })
@@ -370,3 +384,68 @@ enum AlignmentEnum {
370384
_Align1Shl62 = 1 << 62,
371385
_Align1Shl63 = 1 << 63,
372386
}
387+
388+
#[cfg(kani)]
389+
#[unstable(feature="kani", issue="none")]
390+
mod verify {
391+
use super::*;
392+
393+
impl kani::Arbitrary for Alignment {
394+
fn any() -> Self {
395+
let align = kani::any_where(|a: &usize| a.is_power_of_two());
396+
unsafe { mem::transmute::<usize, Alignment>(align) }
397+
}
398+
}
399+
400+
// pub const fn of<T>() -> Self
401+
#[kani::proof_for_contract(Alignment::of)]
402+
pub fn check_of_i32() {
403+
let _ = Alignment::of::<i32>();
404+
}
405+
406+
// pub const fn new(align: usize) -> Option<Self>
407+
#[kani::proof_for_contract(Alignment::new)]
408+
pub fn check_new() {
409+
let a = kani::any::<usize>();
410+
let _ = Alignment::new(a);
411+
}
412+
413+
// pub const unsafe fn new_unchecked(align: usize) -> Self
414+
#[kani::proof_for_contract(Alignment::new_unchecked)]
415+
pub fn check_new_unchecked() {
416+
let a = kani::any::<usize>();
417+
unsafe {
418+
let _ = Alignment::new_unchecked(a);
419+
}
420+
}
421+
422+
// pub const fn as_usize(self) -> usize
423+
#[kani::proof_for_contract(Alignment::as_usize)]
424+
pub fn check_as_usize() {
425+
let a = kani::any::<usize>();
426+
if let Some(alignment) = Alignment::new(a) {
427+
assert_eq!(alignment.as_usize(), a);
428+
}
429+
}
430+
431+
// pub const fn as_nonzero(self) -> NonZero<usize>
432+
#[kani::proof_for_contract(Alignment::as_nonzero)]
433+
pub fn check_as_nonzero() {
434+
let alignment = kani::any::<Alignment>();
435+
let _ = alignment.as_nonzero();
436+
}
437+
438+
// pub const fn log2(self) -> u32
439+
#[kani::proof_for_contract(Alignment::log2)]
440+
pub fn check_log2() {
441+
let alignment = kani::any::<Alignment>();
442+
let _ = alignment.log2();
443+
}
444+
445+
// pub const fn mask(self) -> usize
446+
#[kani::proof_for_contract(Alignment::mask)]
447+
pub fn check_mask() {
448+
let alignment = kani::any::<Alignment>();
449+
let _ = alignment.mask();
450+
}
451+
}

0 commit comments

Comments
 (0)