@@ -3616,152 +3616,129 @@ 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" ) ;
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+ }
36503643
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 > ( ) ;
36553646
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 ( )
36623650 }
3651+ }
36633652
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
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- }
37323703
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) ]
37383704 #[ 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 ( ) ) }
37453717 }
37463718
37473719 #[ kani:: proof_for_contract( copy_nonoverlapping) ]
37483720 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 ( ) ) }
37563733 }
37573734
37583735 #[ kani:: proof_for_contract( write_bytes) ]
37593736 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 ( ) ) }
37663743 }
37673744}
0 commit comments