Skip to content

Commit 6827756

Browse files
committed
Clean up arbitrary pointer
1 parent 87dc890 commit 6827756

File tree

1 file changed

+97
-103
lines changed

1 file changed

+97
-103
lines changed

library/core/src/intrinsics.rs

+97-103
Original file line numberDiff line numberDiff line change
@@ -3616,152 +3616,146 @@ mod verify {
36163616
assert_eq!(x, old_y);
36173617
}
36183618

3619-
/// Note that in `core` we cannot check allocated pointers.
36203619
#[derive(Copy, Clone, Debug, PartialEq, Eq, kani::Arbitrary)]
3621-
enum PtrKind {
3620+
enum AllocationStatus {
36223621
/// Dangling pointers
36233622
Dangling,
3623+
/// Pointer to dead object
3624+
DeadObj,
36243625
/// Null pointers
36253626
Null,
3626-
/// Stack pointers
3627-
Stack,
3628-
/// Overlapping pointers
3629-
Overlap,
3630-
/// Unaligned pointers
3631-
Unaligned,
3632-
/// Pointer to uninitialized memory
3633-
Uninitialized,
3627+
/// In bounds pointer (it may be unaligned)
3628+
InBounds,
3629+
/// Out of bounds
3630+
OutBounds,
36343631
}
36353632

3636-
struct ArbitraryPointers<T> {
3637-
src: *const T,
3638-
dst: *mut T,
3639-
dst_kind: PtrKind,
3640-
src_kind: PtrKind,
3633+
struct PointerGenerator<T, const BUF_LEN: usize> {
3634+
// Internal allocation that may be used to generate valid pointers.
3635+
buf: MaybeUninit<[T; BUF_LEN]>,
36413636
}
36423637

3643-
impl<T: kani::Arbitrary> ArbitraryPointers<T> {
3644-
const MAX_SIZE_T: usize = 100;
3645-
const SIZE_T: usize = size_of::<T>();
3646-
3647-
const IS_VALID: () = assert!(Self::SIZE_T < Self::MAX_SIZE_T, "Exceeded supported type size");
3638+
struct ArbitraryPointer<T> {
3639+
pub ptr: *mut T,
3640+
pub status: AllocationStatus,
3641+
pub is_initialized: bool,
3642+
}
36483643

3649-
fn with_arbitrary<F>(harness: F) where F: FnOnce(ArbitraryPointers<T>) {
3644+
impl<T: kani::Arbitrary, const BUF_LEN: usize> PointerGenerator<T, BUF_LEN> {
3645+
const SZ : usize = BUF_LEN * size_of::<T>();
36503646

3651-
#[repr(C)]
3652-
struct WithUninit<const SIZE: usize> {
3653-
bytes: [MaybeUninit<u8>; SIZE],
3647+
pub fn new() -> Self {
3648+
PointerGenerator {
3649+
buf: MaybeUninit::uninit()
36543650
}
3651+
}
36553652

3656-
#[repr(C)]
3657-
#[repr(packed)]
3658-
#[derive(kani::Arbitrary)]
3659-
struct Unaligned<T> {
3660-
first: u8,
3661-
val: T, // If alignment of T > 1, this value will be unaligned but valid otherwise.
3662-
}
3663-
3664-
let mut single = kani::any::<T>();
3665-
let single_ptr = addr_of_mut!(single);
3666-
3667-
let mut array: [T; 100] = kani::any();
3668-
let array_ptr = addr_of_mut!(array) as *mut T;
3653+
/// Create another ArbitraryPointer that may have the same precedence as the `other` pointer.
3654+
///
3655+
/// I.e.: Non-deterministically derive a pointer from the given pointer or create a new
3656+
/// arbitrary pointer.
3657+
pub fn generate_ptr(&mut self) -> ArbitraryPointer<T> {
3658+
// Create an arbitrary pointer, but leave `ptr` as unset for now.
3659+
let mut arbitrary = ArbitraryPointer {
3660+
ptr: ptr::null_mut::<T>(),
3661+
is_initialized: false,
3662+
status: kani::any(),
3663+
};
36693664

3670-
let mut unaligned: Unaligned<T> = kani::any();
3671-
let unaligned_ptr = addr_of_mut!(unaligned.val) as *mut T;
3665+
let buf_ptr = addr_of_mut!(self.buf) as *mut T;
36723666

3673-
let mut uninit = WithUninit { bytes: [MaybeUninit::zeroed(); Self::MAX_SIZE_T] };
3674-
for i in 0..Self::SIZE_T {
3675-
if kani::any() {
3676-
uninit.bytes[i] = MaybeUninit::uninit();
3667+
// Offset is used to potentially generate unaligned pointer.
3668+
let offset = kani::any_where(|b: &usize| *b < size_of::<T>());
3669+
let ptr = match arbitrary.status {
3670+
AllocationStatus::Dangling => {
3671+
crate::ptr::dangling_mut::<T>().wrapping_add(offset)
36773672
}
3678-
}
3679-
let uninit_ptr = &mut uninit as *mut _ as *mut T;
3680-
3681-
let arbitrary = ArbitraryPointers::from(single_ptr, array_ptr, unaligned_ptr, uninit_ptr);
3682-
harness(arbitrary);
3683-
}
3684-
3685-
fn from(ptr1: *mut T, ptr2: *mut T, unaligned: *mut T, uninit: *mut T) -> Self {
3686-
let (src_kind, src) = ArbitraryPointers::any(ptr1, ptr2, unaligned, uninit);
3687-
let (dst_kind, dst) = ArbitraryPointers::any(ptr2, ptr1, unaligned, uninit);
3688-
ArbitraryPointers {
3689-
src_kind,
3690-
src,
3691-
dst_kind,
3692-
dst,
3693-
}
3694-
}
3695-
3696-
fn any(unique: *mut T, overlap: *mut T, unaligned: *mut T, uninit: *mut T) -> (PtrKind, *mut T) {
3697-
let kind = kani::any::<PtrKind>();
3698-
let ptr = match kind {
3699-
PtrKind::Dangling => {
3700-
crate::ptr::dangling_mut::<T>()
3673+
AllocationStatus::DeadObj => {
3674+
let mut obj: T = kani::any();
3675+
&mut obj as *mut _
37013676
}
3702-
PtrKind::Null => {
3677+
AllocationStatus::Null => {
37033678
crate::ptr::null_mut::<T>()
37043679
}
3705-
PtrKind::Stack => {
3706-
unique
3680+
AllocationStatus::InBounds => {
3681+
let pos = kani::any_where(|i: &usize| *i < (BUF_LEN - 1));
3682+
let ptr: *mut T = buf_ptr.wrapping_add(pos).wrapping_byte_add(offset);
3683+
if kani::any() {
3684+
arbitrary.is_initialized = true;
3685+
// This should be in bounds of arbitrary.alloc.
3686+
unsafe { ptr.write_unaligned(kani::any()) };
3687+
}
3688+
ptr
37073689
}
3708-
PtrKind::Overlap => {
3709-
if kani::any() { unique } else { overlap }
3710-
}
3711-
PtrKind::Unaligned => {
3712-
unaligned
3713-
}
3714-
PtrKind::Uninitialized => {
3715-
uninit
3690+
AllocationStatus::OutBounds => {
3691+
if kani::any() {
3692+
buf_ptr.wrapping_add(BUF_LEN).wrapping_byte_sub(offset)
3693+
} else {
3694+
buf_ptr.wrapping_add(BUF_LEN).wrapping_byte_add(offset)
3695+
}
37163696
}
37173697
};
3718-
(kind, ptr)
3698+
3699+
arbitrary
37193700
}
37203701
}
37213702

3703+
37223704
#[kani::proof_for_contract(copy)]
37233705
fn check_copy() {
3724-
ArbitraryPointers::<u32>::with_arbitrary(|arbitrary| {
3725-
// Skip dangling for now since it makes Kani contract panic.
3726-
// Verify this case in a separate harness.
3727-
kani::assume(arbitrary.dst_kind != PtrKind::Dangling);
3728-
kani::assume(arbitrary.src_kind != PtrKind::Dangling);
3729-
unsafe { copy(arbitrary.src, arbitrary.dst, kani::any()) }
3730-
});
3706+
let mut generator = PointerGenerator::<char, 10>::new();
3707+
let src = generator.generate_ptr();
3708+
let dst = if kani::any() {
3709+
generator.generate_ptr();
3710+
} else {
3711+
PointerGenerator::<char, 10>::new().generate_ptr()
3712+
};
3713+
// Skip dangling for now since it makes Kani contract panic.
3714+
// Verify this case in a separate harness.
3715+
kani::assume(src.status != AllocationStatus::Dangling);
3716+
kani::assume(dst.status != AllocationStatus::Dangling);
3717+
unsafe { copy(src.ptr, dst.ptr, kani::any()) }
37313718
}
37323719

37333720
/// This harness fails because Kani cannot assume a pointer is valid.
37343721
///
37353722
/// The specification should ensure the pointers passed are allocated, and this harness should
37363723
/// succeed since `copy` ensures would reject dangling pointers.
3737-
#[cfg(ignore)]
3724+
#[kani::should_panic]
37383725
#[kani::proof_for_contract(copy)]
37393726
fn check_copy_dangling() {
3740-
ArbitraryPointers::<u32>::with_arbitrary(|arbitrary| {
3727+
let mut generator = PointerGenerator::<char, 10>::new();
3728+
let src = generator.generate_ptr();
3729+
let dst = generator.generate_ptr();
37413730
// Verify the dangling case.
3742-
kani::assume(arbitrary.dst_kind == PtrKind::Dangling || arbitrary.src_kind == PtrKind::Dangling);
3743-
unsafe { copy(arbitrary.src, arbitrary.dst, kani::any()) }
3744-
});
3731+
kani::assume(src.status == AllocationStatus::Dangling || dst.status == AllocationStatus::Dangling);
3732+
unsafe { copy(src.ptr, dst.ptr, kani::any()) }
37453733
}
37463734

37473735
#[kani::proof_for_contract(copy_nonoverlapping)]
37483736
fn check_copy_nonoverlapping() {
3749-
ArbitraryPointers::<u32>::with_arbitrary(|arbitrary| {
3750-
// Skip dangling for now since it makes Kani contract panic.
3751-
// Verify this case in a separate harness.
3752-
kani::assume(arbitrary.dst_kind != PtrKind::Dangling);
3753-
kani::assume(arbitrary.src_kind != PtrKind::Dangling);
3754-
unsafe { copy_nonoverlapping(arbitrary.src, arbitrary.dst, kani::any()) }
3755-
});
3737+
let mut generator = PointerGenerator::<char, 10>::new();
3738+
let src = generator.generate_ptr();
3739+
// Destination may or may not have the same precedence as src.
3740+
let dst = if kani::any() {
3741+
generator.generate_ptr();
3742+
} else {
3743+
PointerGenerator::<char, 10>::new().generate_ptr()
3744+
};
3745+
// Skip dangling for now since it makes Kani contract panic.
3746+
// Verify this case in a separate harness.
3747+
kani::assume(src.status != AllocationStatus::Dangling);
3748+
kani::assume(dst.status != AllocationStatus::Dangling);
3749+
unsafe { copy_nonoverlapping(src.ptr, dst.ptr, kani::any()) }
37563750
}
37573751

37583752
#[kani::proof_for_contract(write_bytes)]
37593753
fn check_write_bytes() {
3760-
ArbitraryPointers::<u32>::with_arbitrary(|arbitrary| {
3761-
// Skip dangling for now since it makes Kani contract panic.
3762-
// Verify this case in a separate harness.
3763-
kani::assume(arbitrary.dst_kind != PtrKind::Dangling);
3764-
unsafe { write_bytes(arbitrary.dst, kani::any(), kani::any()) }
3765-
});
3754+
let mut generator = PointerGenerator::<char, 10>::new();
3755+
let src = generator.generate_ptr();
3756+
kani::assume(src.status != AllocationStatus::Dangling);
3757+
// Skip dangling for now since it makes Kani contract panic.
3758+
// Verify this case in a separate harness.
3759+
unsafe { write_bytes(src.ptr, kani::any(), kani::any()) }
37663760
}
37673761
}

0 commit comments

Comments
 (0)