Skip to content

Commit 18b61ff

Browse files
committed
Final adjustments and remove metadata functions
1 parent 5fc28bd commit 18b61ff

File tree

2 files changed

+77
-231
lines changed

2 files changed

+77
-231
lines changed

library/core/src/intrinsics.rs

Lines changed: 77 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@
6363
)]
6464
#![allow(missing_docs)]
6565

66-
use safety::{ensures, requires};
6766
use crate::marker::DiscriminantKind;
6867
use crate::marker::Tuple;
6968
use crate::ptr;
7069
use crate::ub_checks;
70+
use safety::{ensures, requires};
7171

7272
#[cfg(kani)]
7373
use crate::kani;
@@ -77,12 +77,19 @@ pub mod simd;
7777

7878
// These imports are used for simplifying intra-doc links
7979
#[allow(unused_imports)]
80-
#[cfg(all(target_has_atomic = "8", target_has_atomic = "32", target_has_atomic = "ptr"))]
80+
#[cfg(all(
81+
target_has_atomic = "8",
82+
target_has_atomic = "32",
83+
target_has_atomic = "ptr"
84+
))]
8185
use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering};
8286

8387
#[stable(feature = "drop_in_place", since = "1.8.0")]
8488
#[rustc_allowed_through_unstable_modules]
85-
#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")]
89+
#[deprecated(
90+
note = "no longer an intrinsic - use `ptr::drop_in_place` directly",
91+
since = "1.52.0"
92+
)]
8693
#[inline]
8794
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
8895
// SAFETY: see `ptr::drop_in_place`
@@ -1032,7 +1039,11 @@ pub const fn unlikely(b: bool) -> bool {
10321039
#[miri::intrinsic_fallback_is_spec]
10331040
#[inline]
10341041
pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
1035-
if b { true_val } else { false_val }
1042+
if b {
1043+
true_val
1044+
} else {
1045+
false_val
1046+
}
10361047
}
10371048

10381049
extern "rust-intrinsic" {
@@ -2937,7 +2948,7 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
29372948
#[requires(ub_checks::can_dereference(x) && ub_checks::can_write(x))]
29382949
#[requires(ub_checks::can_dereference(y) && ub_checks::can_write(y))]
29392950
#[requires(x.addr() != y.addr() || core::mem::size_of::<T>() == 0)]
2940-
#[requires(ub_checks::is_nonoverlapping(x as *const (), x as *const (), size_of::<T>(), 1))]
2951+
#[requires(ub_checks::is_nonoverlapping(x as *const (), y as *const (), size_of::<T>(), 1))]
29412952
#[ensures(|_| ub_checks::can_dereference(x) && ub_checks::can_dereference(y))]
29422953
pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
29432954
// SAFETY: The caller provided single non-overlapping items behind
@@ -3013,9 +3024,9 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
30133024
#[unstable(feature = "core_intrinsics", issue = "none")]
30143025
#[rustc_intrinsic]
30153026
#[rustc_intrinsic_must_be_overridden]
3016-
// FIXME(kani): Cannot verify intrinsics contract yet.
3017-
// <https://github.com/model-checking/kani/issues/3345>
3018-
#[requires(ub_checks::can_dereference(_ptr as *const crate::ptr::DynMetadata<dyn crate::any::Any>))]
3027+
// VTable pointers must be valid for dereferencing at least 3 `usize` (size, alignment and drop):
3028+
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/166>
3029+
#[requires(ub_checks::can_dereference(_ptr as *const [usize; 3]))]
30193030
pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
30203031
unreachable!()
30213032
}
@@ -3029,9 +3040,9 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
30293040
#[unstable(feature = "core_intrinsics", issue = "none")]
30303041
#[rustc_intrinsic]
30313042
#[rustc_intrinsic_must_be_overridden]
3032-
// FIXME(kani): Cannot verify intrinsics contract yet.
3033-
// <https://github.com/model-checking/kani/issues/3345>
3034-
#[requires(ub_checks::can_dereference(_ptr as *const crate::ptr::DynMetadata<dyn crate::any::Any>))]
3043+
// VTable pointers must be valid for dereferencing at least 3 `usize` (size, alignment and drop):
3044+
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/166>
3045+
#[requires(ub_checks::can_dereference(_ptr as *const [usize; 3]))]
30353046
pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
30363047
unreachable!()
30373048
}
@@ -3116,14 +3127,6 @@ pub const fn variant_count<T>() -> usize {
31163127
#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
31173128
#[rustc_intrinsic]
31183129
#[rustc_intrinsic_must_be_overridden]
3119-
#[cfg_attr(not(kani), requires(matches!(
3120-
<T as Pointee>::Metadata::map_dyn(crate::ptr::metadata(_val)::metadata(),
3121-
|dyn_meta| { ub_checks::can_dereference(dyn_meta)}),
3122-
None | Some(true))))]
3123-
#[cfg_attr(not(kani), requires(matches!(
3124-
<T as Pointee>::Metadata::map_len(crate::ptr::metadata(_val)::metadata(),
3125-
|_| { ub_checks::can_dereference(_val)}),
3126-
None | Some(true))))]
31273130
pub const unsafe fn size_of_val<T: ?Sized>(_ptr: *const T) -> usize {
31283131
unreachable!()
31293132
}
@@ -3324,7 +3327,6 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons
33243327
&& ub_checks::can_write(core::ptr::slice_from_raw_parts_mut(dst, count))
33253328
&& ub_checks::is_nonoverlapping(src as *const (), dst as *const (), size_of::<T>(), count))]
33263329
#[ensures(|_| { check_copy_untyped(src, dst, count)})]
3327-
#[cfg_attr(kani, kani::modifies(crate::ptr::slice_from_raw_parts(dst, count)))]
33283330
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
33293331
extern "rust-intrinsic" {
33303332
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
@@ -3517,7 +3519,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
35173519
#[rustc_diagnostic_item = "ptr_write_bytes"]
35183520
#[requires(!count.overflowing_mul(size_of::<T>()).1
35193521
&& ub_checks::can_write(core::ptr::slice_from_raw_parts_mut(dst, count)))]
3520-
#[requires(count > 0 || ub_checks::is_aligned_and_not_null(dst as *const (), align_of::<T>()))]
3522+
#[requires(ub_checks::is_aligned_and_not_null(dst as *const (), align_of::<T>()))]
35213523
#[ensures(|_|
35223524
ub_checks::can_dereference(crate::ptr::slice_from_raw_parts(dst as *const u8, count * size_of::<T>())))]
35233525
#[cfg_attr(kani, kani::modifies(crate::ptr::slice_from_raw_parts(dst, count)))]
@@ -3551,10 +3553,10 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
35513553
fn check_copy_untyped<T>(src: *const T, dst: *mut T, count: usize) -> bool {
35523554
#[cfg(kani)]
35533555
if count > 0 {
3554-
let byte = kani::any_where(| sz: &usize | *sz < size_of::< T >());
3555-
let elem = kani::any_where(| val: &usize | *val < count);
3556-
let src_data = src as * const u8;
3557-
let dst_data = unsafe { dst.add(elem) } as * const u8;
3556+
let byte = kani::any_where(|sz: &usize| *sz < size_of::<T>());
3557+
let elem = kani::any_where(|val: &usize| *val < count);
3558+
let src_data = src as *const u8;
3559+
let dst_data = unsafe { dst.add(elem) } as *const u8;
35583560
ub_checks::can_dereference(unsafe { src_data.add(byte) })
35593561
== ub_checks::can_dereference(unsafe { dst_data.add(byte) })
35603562
} else {
@@ -3587,163 +3589,81 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
35873589
}
35883590

35893591
#[cfg(kani)]
3590-
#[unstable(feature="kani", issue="none")]
3592+
#[unstable(feature = "kani", issue = "none")]
35913593
mod verify {
3592-
use core::{cmp, fmt};
3593-
use core::ptr::addr_of_mut;
3594-
use core::mem::MaybeUninit;
35953594
use super::*;
35963595
use crate::kani;
3596+
use core::mem::MaybeUninit;
3597+
use core::ptr::addr_of_mut;
3598+
use core::{cmp, fmt};
3599+
use kani::{AllocationStatus, Arbitrary, ArbitraryPointer, PointerGenerator};
35973600

35983601
#[kani::proof_for_contract(typed_swap)]
35993602
pub fn check_typed_swap_u8() {
3600-
check_swap::<u8>()
3603+
run_with_arbitrary_ptrs::<u8>(|x, y| unsafe { typed_swap(x, y) });
36013604
}
36023605

36033606
#[kani::proof_for_contract(typed_swap)]
36043607
pub fn check_typed_swap_char() {
3605-
check_swap::<char>()
3608+
run_with_arbitrary_ptrs::<char>(|x, y| unsafe { typed_swap(x, y) });
36063609
}
36073610

36083611
#[kani::proof_for_contract(typed_swap)]
36093612
pub fn check_typed_swap_non_zero() {
3610-
check_swap::<core::num::NonZeroI32>()
3611-
}
3612-
3613-
pub fn check_swap<T: kani::Arbitrary + Copy + cmp::PartialEq + fmt::Debug>() {
3614-
let mut x = kani::any::<T>();
3615-
let old_x = x;
3616-
let mut y = kani::any::<T>();
3617-
let old_y = y;
3618-
3619-
unsafe { typed_swap(&mut x, &mut y) };
3620-
assert_eq!(y, old_x);
3621-
assert_eq!(x, old_y);
3613+
run_with_arbitrary_ptrs::<core::num::NonZeroI32>(|x, y| unsafe { typed_swap(x, y) });
36223614
}
36233615

3624-
#[derive(Copy, Clone, Debug, PartialEq, Eq, kani::Arbitrary)]
3625-
enum AllocationStatus {
3626-
/// Dangling pointers
3627-
Dangling,
3628-
/// Pointer to dead object
3629-
DeadObj,
3630-
/// Null pointers
3631-
Null,
3632-
/// In bounds pointer (it may be unaligned)
3633-
InBounds,
3634-
/// Out of bounds
3635-
OutBounds,
3636-
}
3637-
3638-
struct PointerGenerator<T, const BUF_LEN: usize> {
3639-
// Internal allocation that may be used to generate valid pointers.
3640-
buf: MaybeUninit<[T; BUF_LEN]>,
3641-
}
3642-
3643-
struct ArbitraryPointer<T> {
3644-
pub ptr: *mut T,
3645-
pub status: AllocationStatus,
3646-
pub is_initialized: bool,
3647-
}
3648-
3649-
impl<T: kani::Arbitrary, const BUF_LEN: usize> PointerGenerator<T, BUF_LEN> {
3650-
const SZ : usize = BUF_LEN * size_of::<T>();
3651-
3652-
pub fn new() -> Self {
3653-
PointerGenerator {
3654-
buf: MaybeUninit::uninit()
3655-
}
3656-
}
3657-
3658-
/// Create another ArbitraryPointer that may have the same precedence as the `other` pointer.
3659-
///
3660-
/// I.e.: Non-deterministically derive a pointer from the given pointer or create a new
3661-
/// arbitrary pointer.
3662-
pub fn generate_ptr(&mut self) -> ArbitraryPointer<T> {
3663-
// Create an arbitrary pointer, but leave `ptr` as unset for now.
3664-
let mut arbitrary = ArbitraryPointer {
3665-
ptr: ptr::null_mut::<T>(),
3666-
is_initialized: false,
3667-
status: kani::any(),
3668-
};
3669-
3670-
let buf_ptr = addr_of_mut!(self.buf) as *mut T;
3671-
3672-
// Offset is used to potentially generate unaligned pointer.
3673-
let offset = kani::any_where(|b: &usize| *b < size_of::<T>());
3674-
let ptr = match arbitrary.status {
3675-
AllocationStatus::Dangling => {
3676-
crate::ptr::dangling_mut::<T>().wrapping_add(offset)
3677-
}
3678-
AllocationStatus::DeadObj => {
3679-
let mut obj: T = kani::any();
3680-
&mut obj as *mut _
3681-
}
3682-
AllocationStatus::Null => {
3683-
crate::ptr::null_mut::<T>()
3684-
}
3685-
AllocationStatus::InBounds => {
3686-
let pos = kani::any_where(|i: &usize| *i < (BUF_LEN - 1));
3687-
let ptr: *mut T = buf_ptr.wrapping_add(pos).wrapping_byte_add(offset);
3688-
if kani::any() {
3689-
arbitrary.is_initialized = true;
3690-
// This should be in bounds of arbitrary.alloc.
3691-
unsafe { ptr.write_unaligned(kani::any()) };
3692-
}
3693-
ptr
3694-
}
3695-
AllocationStatus::OutBounds => {
3696-
if kani::any() {
3697-
buf_ptr.wrapping_add(BUF_LEN).wrapping_byte_sub(offset)
3698-
} else {
3699-
buf_ptr.wrapping_add(BUF_LEN).wrapping_byte_add(offset)
3700-
}
3701-
}
3702-
};
3703-
3704-
arbitrary
3705-
}
3706-
}
3707-
3708-
37093616
#[kani::proof_for_contract(copy)]
37103617
fn check_copy() {
3711-
let mut generator = PointerGenerator::<char, 10>::new();
3712-
let src = generator.generate_ptr();
3713-
let dst = if kani::any() {
3714-
generator.generate_ptr()
3715-
} else {
3716-
PointerGenerator::<char, 10>::new().generate_ptr()
3717-
};
3718-
// Skip dangling for now since it makes Kani contract panic.
3719-
kani::assume(src.status != AllocationStatus::Dangling);
3720-
kani::assume(dst.status != AllocationStatus::Dangling);
3721-
unsafe { copy(src.ptr, dst.ptr, kani::any()) }
3618+
run_with_arbitrary_ptrs::<char>(|src, dst| unsafe { copy(src, dst, kani::any()) });
37223619
}
37233620

37243621
#[kani::proof_for_contract(copy_nonoverlapping)]
37253622
fn check_copy_nonoverlapping() {
3726-
let mut generator = PointerGenerator::<char, 10>::new();
3727-
let src = generator.generate_ptr();
3728-
// Destination may or may not have the same provenance as src.
3729-
let dst = if kani::any() {
3730-
generator.generate_ptr()
3731-
} else {
3732-
PointerGenerator::<char, 10>::new().generate_ptr()
3733-
};
3734-
// Skip dangling for now since it makes Kani contract panic.
3735-
kani::assume(src.status != AllocationStatus::Dangling);
3736-
kani::assume(dst.status != AllocationStatus::Dangling);
3737-
unsafe { copy_nonoverlapping(src.ptr, dst.ptr, kani::any()) }
3623+
run_with_arbitrary_ptrs::<char>(|src, dst| unsafe {
3624+
copy_nonoverlapping(src, dst, kani::any())
3625+
});
37383626
}
37393627

37403628
#[kani::proof_for_contract(write_bytes)]
37413629
fn check_write_bytes() {
3742-
let mut generator = PointerGenerator::<char, 10>::new();
3743-
let src = generator.generate_ptr();
3744-
kani::assume(src.status != AllocationStatus::Dangling);
3745-
// Skip dangling for now since it makes Kani contract panic.
3746-
// Verify this case in a separate harness.
3747-
unsafe { write_bytes(src.ptr, kani::any(), kani::any()) }
3630+
let mut generator = PointerGenerator::<100>::new();
3631+
let ArbitraryPointer {
3632+
ptr: src,
3633+
status: src_status,
3634+
..
3635+
} = generator.any_alloc_status::<char>();
3636+
kani::assume(supported_status(src_status));
3637+
unsafe { write_bytes(src, kani::any(), kani::any()) };
3638+
}
3639+
3640+
fn run_with_arbitrary_ptrs<T: Arbitrary>(harness: impl Fn(*mut T, *mut T)) {
3641+
let mut generator1 = PointerGenerator::<100>::new();
3642+
let mut generator2 = PointerGenerator::<100>::new();
3643+
let ArbitraryPointer {
3644+
ptr: src,
3645+
status: src_status,
3646+
..
3647+
} = generator1.any_alloc_status::<T>();
3648+
let ArbitraryPointer {
3649+
ptr: dst,
3650+
status: dst_status,
3651+
..
3652+
} = if kani::any() {
3653+
generator1.any_alloc_status::<T>()
3654+
} else {
3655+
generator2.any_alloc_status::<T>()
3656+
};
3657+
kani::assume(supported_status(src_status));
3658+
kani::assume(supported_status(dst_status));
3659+
harness(src, dst);
3660+
}
3661+
3662+
/// Return whether the current status is supported by Kani's contract.
3663+
///
3664+
/// Kani memory predicates currently doesn't support pointers to dangling or dead allocations.
3665+
/// Thus, we have to explicitly exclude those cases.
3666+
fn supported_status(status: AllocationStatus) -> bool {
3667+
status != AllocationStatus::Dangling && status != AllocationStatus::DeadObject
37483668
}
37493669
}

0 commit comments

Comments
 (0)