@@ -3616,152 +3616,129 @@ mod verify {
3616
3616
assert_eq ! ( x, old_y) ;
3617
3617
}
3618
3618
3619
- /// Note that in `core` we cannot check allocated pointers.
3620
3619
#[ derive( Copy , Clone , Debug , PartialEq , Eq , kani:: Arbitrary ) ]
3621
- enum PtrKind {
3620
+ enum AllocationStatus {
3622
3621
/// Dangling pointers
3623
3622
Dangling ,
3623
+ /// Pointer to dead object
3624
+ DeadObj ,
3624
3625
/// Null pointers
3625
3626
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 ,
3634
3631
}
3635
3632
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 ] > ,
3641
3636
}
3642
3637
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" ) ;
3648
-
3649
- fn with_arbitrary < F > ( harness : F ) where F : FnOnce ( ArbitraryPointers < T > ) {
3638
+ struct ArbitraryPointer < T > {
3639
+ pub ptr : * mut T ,
3640
+ pub status : AllocationStatus ,
3641
+ pub is_initialized : bool ,
3642
+ }
3650
3643
3651
- #[ repr( C ) ]
3652
- struct WithUninit < const SIZE : usize > {
3653
- bytes : [ MaybeUninit < u8 > ; SIZE ] ,
3654
- }
3644
+ impl < T : kani:: Arbitrary , const BUF_LEN : usize > PointerGenerator < T , BUF_LEN > {
3645
+ const SZ : usize = BUF_LEN * size_of :: < T > ( ) ;
3655
3646
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.
3647
+ pub fn new ( ) -> Self {
3648
+ PointerGenerator {
3649
+ buf : MaybeUninit :: uninit ( )
3662
3650
}
3651
+ }
3663
3652
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
+ } ;
3669
3664
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 ;
3672
3666
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)
3677
3672
}
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 _
3701
3676
}
3702
- PtrKind :: Null => {
3677
+ AllocationStatus :: Null => {
3703
3678
crate :: ptr:: null_mut :: < T > ( )
3704
3679
}
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
3707
3689
}
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
+ }
3716
3696
}
3717
3697
} ;
3718
- ( kind, ptr)
3698
+
3699
+ arbitrary
3719
3700
}
3720
3701
}
3721
3702
3722
- #[ kani:: proof_for_contract( copy) ]
3723
- 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
- } ) ;
3731
- }
3732
3703
3733
- /// This harness fails because Kani cannot assume a pointer is valid.
3734
- ///
3735
- /// The specification should ensure the pointers passed are allocated, and this harness should
3736
- /// succeed since `copy` ensures would reject dangling pointers.
3737
- #[ cfg( ignore) ]
3738
3704
#[ kani:: proof_for_contract( copy) ]
3739
- fn check_copy_dangling ( ) {
3740
- ArbitraryPointers :: < u32 > :: with_arbitrary ( |arbitrary| {
3741
- // 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
- } ) ;
3705
+ fn check_copy ( ) {
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
+ kani:: assume ( src. status != AllocationStatus :: Dangling ) ;
3715
+ kani:: assume ( dst. status != AllocationStatus :: Dangling ) ;
3716
+ unsafe { copy ( src. ptr , dst. ptr , kani:: any ( ) ) }
3745
3717
}
3746
3718
3747
3719
#[ kani:: proof_for_contract( copy_nonoverlapping) ]
3748
3720
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
- } ) ;
3721
+ let mut generator = PointerGenerator :: < char , 10 > :: new ( ) ;
3722
+ let src = generator. generate_ptr ( ) ;
3723
+ // Destination may or may not have the same precedence as src.
3724
+ let dst = if kani:: any ( ) {
3725
+ generator. generate_ptr ( ) ;
3726
+ } else {
3727
+ PointerGenerator :: < char , 10 > :: new ( ) . generate_ptr ( )
3728
+ } ;
3729
+ // Skip dangling for now since it makes Kani contract panic.
3730
+ kani:: assume ( src. status != AllocationStatus :: Dangling ) ;
3731
+ kani:: assume ( dst. status != AllocationStatus :: Dangling ) ;
3732
+ unsafe { copy_nonoverlapping ( src. ptr , dst. ptr , kani:: any ( ) ) }
3756
3733
}
3757
3734
3758
3735
#[ kani:: proof_for_contract( write_bytes) ]
3759
3736
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
- } ) ;
3737
+ let mut generator = PointerGenerator :: < char , 10 > :: new ( ) ;
3738
+ let src = generator . generate_ptr ( ) ;
3739
+ kani :: assume ( src . status != AllocationStatus :: Dangling ) ;
3740
+ // Skip dangling for now since it makes Kani contract panic.
3741
+ // Verify this case in a separate harness.
3742
+ unsafe { write_bytes ( src . ptr , kani :: any ( ) , kani :: any ( ) ) }
3766
3743
}
3767
3744
}
0 commit comments