6363) ]
6464#![ allow( missing_docs) ]
6565
66- use safety:: { ensures, requires} ;
6766use crate :: marker:: DiscriminantKind ;
6867use crate :: marker:: Tuple ;
6968use crate :: ptr;
7069use crate :: ub_checks;
70+ use safety:: { ensures, requires} ;
7171
7272#[ cfg( kani) ]
7373use 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+ ) ) ]
8185use 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]
8794pub 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]
10341041pub 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
10381049extern "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) ) ]
29422953pub 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 ] ) ) ]
30193030pub 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 ] ) ) ]
30353046pub 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 ) ) ) ) ]
31273130pub 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) ) ) ]
33283330pub 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) {
35513553fn 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" ) ]
35913593mod 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