@@ -519,3 +519,232 @@ mod tests {
519519 }
520520 }
521521}
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