@@ -519,3 +519,232 @@ mod tests {
519
519
}
520
520
}
521
521
}
522
+
523
+ #[ cfg( kani) ]
524
+ mod proofs {
525
+ use crate :: { SizeInfo , TrailingSliceLayout } ;
526
+
527
+ use super :: * ;
528
+
529
+ impl < T > kani:: Arbitrary for PtrInner < ' static , T >
530
+ where
531
+ T : ?Sized + KnownLayout ,
532
+ {
533
+ fn any ( ) -> Self {
534
+ let ( size, meta) = match T :: LAYOUT . size_info {
535
+ SizeInfo :: Sized { size } => ( size, T :: PointerMetadata :: from_elem_count ( 0 ) ) ,
536
+ SizeInfo :: SliceDst ( TrailingSliceLayout { .. } ) => {
537
+ let meta = T :: PointerMetadata :: from_elem_count ( kani:: any ( ) ) ;
538
+ let size = meta. size_for_metadata ( T :: LAYOUT ) ;
539
+ kani:: assume ( size. is_some ( ) ) ;
540
+ let size = size. unwrap ( ) ;
541
+ kani:: assume ( size <= isize:: MAX as usize ) ;
542
+
543
+ ( size, meta)
544
+ }
545
+ } ;
546
+
547
+ let layout =
548
+ alloc:: alloc:: Layout :: from_size_align ( size, T :: LAYOUT . align . get ( ) ) . unwrap ( ) ;
549
+
550
+ let ptr = if layout. size ( ) == 0 {
551
+ NonNull :: dangling ( )
552
+ } else {
553
+ let ptr = unsafe { alloc:: alloc:: alloc ( layout) } ;
554
+ NonNull :: new ( ptr) . unwrap_or_else ( || alloc:: alloc:: handle_alloc_error ( layout) )
555
+ } ;
556
+
557
+ let ptr = T :: raw_from_ptr_len ( ptr, meta) ;
558
+ unsafe { PtrInner :: new ( ptr) }
559
+ }
560
+ }
561
+
562
+ impl < ' a , T > PtrInner < ' a , T >
563
+ where
564
+ T : ?Sized + KnownLayout ,
565
+ {
566
+ fn assert_invariants ( & self ) {
567
+ let ptr = self . as_non_null ( ) ;
568
+ let size = T :: size_of_val_raw ( ptr) . unwrap ( ) ;
569
+ assert ! ( size <= isize :: MAX as usize ) ;
570
+
571
+ let addr = ptr. addr ( ) . get ( ) ;
572
+ // Assert that the referent doesn't wrap around the address space.
573
+ assert ! ( addr. checked_add( size) . is_some( ) ) ;
574
+ }
575
+ }
576
+
577
+ macro_rules! prove_foreach {
578
+ ( $generic: ident { $( $concrete: ident = $ty: ty, ) * } ) => {
579
+ $(
580
+ #[ kani:: proof]
581
+ fn $concrete( ) {
582
+ $generic:: <$ty>( ) ;
583
+ }
584
+ ) *
585
+ } ;
586
+ }
587
+
588
+ fn prove_arbitrary < T : ' static + ?Sized + KnownLayout > ( ) {
589
+ let ptr: PtrInner < ' static , T > = kani:: any ( ) ;
590
+ ptr. assert_invariants ( ) ;
591
+ }
592
+
593
+ // On 64-bit targets, Rust uses 2^61 - 1 rather than 2^63 - 1 as the maximum
594
+ // object size [1].
595
+ //
596
+ // [1] https://github.com/rust-lang/rust/blob/493c38ba371929579fe136df26eccd9516347c7a/compiler/rustc_abi/src/lib.rs#L410
597
+ const MAX_SIZE : usize = 1 << 61 - 1 ;
598
+
599
+ prove_foreach ! {
600
+ prove_arbitrary {
601
+ prove_arbitrary_empty_tuple = ( ) ,
602
+ prove_arbitrary_u8 = u8 ,
603
+ prove_arbitrary_u16 = u16 ,
604
+ prove_arbitrary_slice_u8 = [ u8 ] ,
605
+ prove_arbitrary_slice_u16 = [ u16 ] ,
606
+ prove_arbitrary_large_u8 = [ u8 ; MAX_SIZE ] ,
607
+ prove_arbitrary_large_slice_u8 = [ [ u8 ; MAX_SIZE ] ] ,
608
+ prove_arbitrary_large_u16 = [ u16 ; ( MAX_SIZE ) /2 ] ,
609
+ prove_arbitrary_large_slice_u16 = [ [ u16 ; ( MAX_SIZE ) /2 ] ] ,
610
+ }
611
+ }
612
+
613
+ fn prove_slice_unchecked < T : ' static > ( ) {
614
+ let ptr: PtrInner < ' static , [ T ] > = kani:: any ( ) ;
615
+ let start = kani:: any ( ) ;
616
+ let end = kani:: any ( ) ;
617
+
618
+ kani:: assume ( start <= end) ;
619
+ kani:: assume ( end <= ptr. len ( ) ) ;
620
+
621
+ let slc = unsafe { ptr. slice_unchecked ( Range { start, end } ) } ;
622
+ slc. assert_invariants ( ) ;
623
+
624
+ assert_eq ! ( slc. len( ) , end - start) ;
625
+
626
+ let begin = unsafe { slc. as_non_null ( ) . cast :: < T > ( ) . sub ( start) } ;
627
+ assert_eq ! ( begin, ptr. as_non_null( ) . cast:: <T >( ) ) ;
628
+ }
629
+
630
+ prove_foreach ! {
631
+ prove_slice_unchecked {
632
+ prove_slice_unchecked_empty_tuple = ( ) ,
633
+ prove_slice_unchecked_u8 = u8 ,
634
+ prove_slice_unchecked_u16 = u16 ,
635
+ prove_slice_unchecked_large_u8 = [ u8 ; MAX_SIZE ] ,
636
+ prove_slice_unchecked_large_u16 = [ u16 ; ( MAX_SIZE ) /2 ] ,
637
+ }
638
+ }
639
+
640
+ fn prove_split_at < T : ' static > ( ) {
641
+ let ptr: PtrInner < ' static , [ T ] > = kani:: any ( ) ;
642
+ let l_len = kani:: any ( ) ;
643
+
644
+ kani:: assume ( l_len <= ptr. len ( ) ) ;
645
+
646
+ let ( left, right) = unsafe { ptr. split_at ( l_len) } ;
647
+ left. assert_invariants ( ) ;
648
+ right. assert_invariants ( ) ;
649
+
650
+ assert_eq ! ( left. len( ) , l_len) ;
651
+ assert_eq ! ( left. len( ) + right. len( ) , ptr. len( ) ) ;
652
+ assert_eq ! ( left. as_non_null( ) . cast:: <T >( ) , ptr. as_non_null( ) . cast:: <T >( ) ) ;
653
+ }
654
+
655
+ prove_foreach ! {
656
+ prove_split_at {
657
+ prove_split_at_empty_tuple = ( ) ,
658
+ prove_split_at_u8 = u8 ,
659
+ prove_split_at_u16 = u16 ,
660
+ prove_split_at_large_u8 = [ u8 ; MAX_SIZE ] ,
661
+ prove_split_at_large_u16 = [ u16 ; ( MAX_SIZE ) /2 ] ,
662
+ }
663
+ }
664
+
665
+ #[ kani:: proof]
666
+ fn prove_as_slice ( ) {
667
+ fn inner < T : ' static , const N : usize > ( ) {
668
+ let ptr: PtrInner < ' static , [ T ; N ] > = kani:: any ( ) ;
669
+ let slc = ptr. as_slice ( ) ;
670
+ slc. assert_invariants ( ) ;
671
+
672
+ assert_eq ! ( ptr. as_non_null( ) . cast:: <T >( ) , slc. as_non_null( ) . cast:: <T >( ) ) ;
673
+ assert_eq ! ( slc. len( ) , N ) ;
674
+ }
675
+
676
+ inner :: < ( ) , 0 > ( ) ;
677
+ inner :: < ( ) , 1 > ( ) ;
678
+ inner :: < ( ) , MAX_SIZE > ( ) ;
679
+
680
+ inner :: < u8 , 0 > ( ) ;
681
+ inner :: < u8 , 1 > ( ) ;
682
+ inner :: < u8 , MAX_SIZE > ( ) ;
683
+
684
+ inner :: < [ u8 ; MAX_SIZE / 2 ] , 0 > ( ) ;
685
+ inner :: < [ u8 ; MAX_SIZE / 2 ] , 1 > ( ) ;
686
+ inner :: < [ u8 ; MAX_SIZE / 2 ] , 2 > ( ) ;
687
+
688
+ inner :: < [ u8 ; MAX_SIZE ] , 0 > ( ) ;
689
+ inner :: < [ u8 ; MAX_SIZE ] , 1 > ( ) ;
690
+ }
691
+
692
+ impl kani:: Arbitrary for CastType {
693
+ fn any ( ) -> CastType {
694
+ if kani:: any ( ) {
695
+ CastType :: Prefix
696
+ } else {
697
+ CastType :: Suffix
698
+ }
699
+ }
700
+ }
701
+
702
+ fn prove_try_cast_into < T : ' static + ?Sized + KnownLayout > ( ) {
703
+ let ptr: PtrInner < ' static , [ u8 ] > = kani:: any ( ) ;
704
+ let cast_type = kani:: any ( ) ;
705
+ let meta = kani:: any ( ) ;
706
+
707
+ match ptr. try_cast_into :: < T > ( cast_type, meta) {
708
+ Ok ( ( t, rest) ) => {
709
+ t. assert_invariants ( ) ;
710
+
711
+ let ptr_u8 = ptr. as_non_null ( ) . cast :: < u8 > ( ) ;
712
+ let t_u8 = t. as_non_null ( ) . cast :: < u8 > ( ) ;
713
+ let rest_u8 = rest. as_non_null ( ) . cast :: < u8 > ( ) ;
714
+ match cast_type {
715
+ CastType :: Prefix => {
716
+ assert_eq ! ( t_u8, ptr_u8) ;
717
+ // TODO: Assert that `t` and `rest` are contiguous and
718
+ // non-overlapping.
719
+ }
720
+ CastType :: Suffix => {
721
+ assert_eq ! ( rest_u8, ptr_u8) ;
722
+ // Asserts that `rest` and `t` are contiguous and
723
+ // non-overlapping.
724
+ assert_eq ! ( unsafe { rest_u8. add( rest. len( ) ) } , t_u8) ;
725
+ }
726
+ }
727
+ }
728
+ Err ( CastError :: Alignment ( _) ) => {
729
+ // TODO: Prove that there would have been an alignment problem.
730
+ }
731
+ Err ( CastError :: Size ( _) ) => {
732
+ // TODO: Prove that there would have been a size problem.
733
+ }
734
+ }
735
+ }
736
+
737
+ prove_foreach ! {
738
+ prove_try_cast_into {
739
+ prove_try_cast_into_empty_tuple = ( ) ,
740
+ prove_try_cast_into_u8 = u8 ,
741
+ prove_try_cast_into_u16 = u16 ,
742
+ prove_try_cast_into_slice_u8 = [ u8 ] ,
743
+ prove_try_cast_into_slice_u16 = [ u16 ] ,
744
+ prove_try_cast_into_large_u8 = [ u8 ; MAX_SIZE ] ,
745
+ prove_try_cast_into_large_slice_u8 = [ [ u8 ; MAX_SIZE ] ] ,
746
+ prove_try_cast_into_large_u16 = [ u16 ; ( MAX_SIZE ) /2 ] ,
747
+ prove_try_cast_into_large_slice_u16 = [ [ u16 ; ( MAX_SIZE ) /2 ] ] ,
748
+ }
749
+ }
750
+ }
0 commit comments