63
63
) ]
64
64
#![ allow( missing_docs) ]
65
65
66
- use safety:: { ensures, requires} ;
67
66
use crate :: marker:: DiscriminantKind ;
68
67
use crate :: marker:: Tuple ;
69
68
use crate :: ptr;
70
69
use crate :: ub_checks;
70
+ use safety:: { ensures, requires} ;
71
71
72
72
#[ cfg( kani) ]
73
73
use crate :: kani;
@@ -77,12 +77,19 @@ pub mod simd;
77
77
78
78
// These imports are used for simplifying intra-doc links
79
79
#[ 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
+ ) ) ]
81
85
use crate :: sync:: atomic:: { self , AtomicBool , AtomicI32 , AtomicIsize , AtomicU32 , Ordering } ;
82
86
83
87
#[ stable( feature = "drop_in_place" , since = "1.8.0" ) ]
84
88
#[ 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
+ ) ]
86
93
#[ inline]
87
94
pub unsafe fn drop_in_place < T : ?Sized > ( to_drop : * mut T ) {
88
95
// SAFETY: see `ptr::drop_in_place`
@@ -1032,7 +1039,11 @@ pub const fn unlikely(b: bool) -> bool {
1032
1039
#[ miri:: intrinsic_fallback_is_spec]
1033
1040
#[ inline]
1034
1041
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
+ }
1036
1047
}
1037
1048
1038
1049
extern "rust-intrinsic" {
@@ -2937,7 +2948,7 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
2937
2948
#[ requires( ub_checks:: can_dereference( x) && ub_checks:: can_write( x) ) ]
2938
2949
#[ requires( ub_checks:: can_dereference( y) && ub_checks:: can_write( y) ) ]
2939
2950
#[ 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 ) ) ]
2941
2952
#[ ensures( |_| ub_checks:: can_dereference( x) && ub_checks:: can_dereference( y) ) ]
2942
2953
pub const unsafe fn typed_swap < T > ( x : * mut T , y : * mut T ) {
2943
2954
// 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)
3013
3024
#[ unstable( feature = "core_intrinsics" , issue = "none" ) ]
3014
3025
#[ rustc_intrinsic]
3015
3026
#[ 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 ] ) ) ]
3019
3030
pub unsafe fn vtable_size ( _ptr : * const ( ) ) -> usize {
3020
3031
unreachable ! ( )
3021
3032
}
@@ -3029,9 +3040,9 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
3029
3040
#[ unstable( feature = "core_intrinsics" , issue = "none" ) ]
3030
3041
#[ rustc_intrinsic]
3031
3042
#[ 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 ] ) ) ]
3035
3046
pub unsafe fn vtable_align ( _ptr : * const ( ) ) -> usize {
3036
3047
unreachable ! ( )
3037
3048
}
@@ -3116,14 +3127,6 @@ pub const fn variant_count<T>() -> usize {
3116
3127
#[ rustc_const_unstable( feature = "const_size_of_val" , issue = "46571" ) ]
3117
3128
#[ rustc_intrinsic]
3118
3129
#[ 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 ) ) ) ) ]
3127
3130
pub const unsafe fn size_of_val < T : ?Sized > ( _ptr : * const T ) -> usize {
3128
3131
unreachable ! ( )
3129
3132
}
@@ -3324,7 +3327,6 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons
3324
3327
&& ub_checks:: can_write( core:: ptr:: slice_from_raw_parts_mut( dst, count) )
3325
3328
&& ub_checks:: is_nonoverlapping( src as * const ( ) , dst as * const ( ) , size_of:: <T >( ) , count) ) ]
3326
3329
#[ ensures( |_| { check_copy_untyped( src, dst, count) } ) ]
3327
- #[ cfg_attr( kani, kani:: modifies( crate :: ptr:: slice_from_raw_parts( dst, count) ) ) ]
3328
3330
pub const unsafe fn copy_nonoverlapping < T > ( src : * const T , dst : * mut T , count : usize ) {
3329
3331
extern "rust-intrinsic" {
3330
3332
#[ 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) {
3517
3519
#[ rustc_diagnostic_item = "ptr_write_bytes" ]
3518
3520
#[ requires( !count. overflowing_mul( size_of:: <T >( ) ) . 1
3519
3521
&& 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 >( ) ) ) ]
3521
3523
#[ ensures( |_|
3522
3524
ub_checks:: can_dereference( crate :: ptr:: slice_from_raw_parts( dst as * const u8 , count * size_of:: <T >( ) ) ) ) ]
3523
3525
#[ 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) {
3551
3553
fn check_copy_untyped < T > ( src : * const T , dst : * mut T , count : usize ) -> bool {
3552
3554
#[ cfg( kani) ]
3553
3555
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 ;
3558
3560
ub_checks:: can_dereference ( unsafe { src_data. add ( byte) } )
3559
3561
== ub_checks:: can_dereference ( unsafe { dst_data. add ( byte) } )
3560
3562
} else {
@@ -3587,163 +3589,81 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
3587
3589
}
3588
3590
3589
3591
#[ cfg( kani) ]
3590
- #[ unstable( feature= "kani" , issue= "none" ) ]
3592
+ #[ unstable( feature = "kani" , issue = "none" ) ]
3591
3593
mod verify {
3592
- use core:: { cmp, fmt} ;
3593
- use core:: ptr:: addr_of_mut;
3594
- use core:: mem:: MaybeUninit ;
3595
3594
use super :: * ;
3596
3595
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 } ;
3597
3600
3598
3601
#[ kani:: proof_for_contract( typed_swap) ]
3599
3602
pub fn check_typed_swap_u8 ( ) {
3600
- check_swap :: < u8 > ( )
3603
+ run_with_arbitrary_ptrs :: < u8 > ( |x , y| unsafe { typed_swap ( x , y ) } ) ;
3601
3604
}
3602
3605
3603
3606
#[ kani:: proof_for_contract( typed_swap) ]
3604
3607
pub fn check_typed_swap_char ( ) {
3605
- check_swap :: < char > ( )
3608
+ run_with_arbitrary_ptrs :: < char > ( |x , y| unsafe { typed_swap ( x , y ) } ) ;
3606
3609
}
3607
3610
3608
3611
#[ kani:: proof_for_contract( typed_swap) ]
3609
3612
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) } ) ;
3622
3614
}
3623
3615
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
-
3709
3616
#[ kani:: proof_for_contract( copy) ]
3710
3617
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 ( ) ) } ) ;
3722
3619
}
3723
3620
3724
3621
#[ kani:: proof_for_contract( copy_nonoverlapping) ]
3725
3622
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
+ } ) ;
3738
3626
}
3739
3627
3740
3628
#[ kani:: proof_for_contract( write_bytes) ]
3741
3629
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
3748
3668
}
3749
3669
}
0 commit comments