@@ -4642,6 +4642,106 @@ mod verify {
4642
4642
let dst = if kani:: any ( ) { gen_any_ptr ( & mut buffer2) } else { gen_any_ptr ( & mut buffer1) } ;
4643
4643
unsafe { copy_nonoverlapping ( src, dst, kani:: any ( ) ) }
4644
4644
}
4645
+
4646
+ //We need this wrapper because transmute_unchecked is an intrinsic, for which Kani does
4647
+ //not currently support contracts (https://github.com/model-checking/kani/issues/3345)
4648
+ #[ requires( crate :: mem:: size_of:: <T >( ) == crate :: mem:: size_of:: <U >( ) ) ] //T and U have same size (transmute_unchecked does not guarantee this)
4649
+ #[ requires( ub_checks:: can_dereference( & input as * const T as * const U ) ) ] //output can be deref'd as value of type U
4650
+ #[ allow( dead_code) ]
4651
+ unsafe fn transmute_unchecked_wrapper < T , U > ( input : T ) -> U {
4652
+ unsafe { transmute_unchecked ( input) }
4653
+ }
4654
+
4655
+ //generates harness that transmutes arbitrary values of input type to output type
4656
+ //use when you expect all resulting bit patterns of output type to be valid
4657
+ macro_rules! transmute_unchecked_should_succeed {
4658
+ ( $harness: ident, $src: ty, $dst: ty) => {
4659
+ #[ kani:: proof_for_contract( transmute_unchecked_wrapper) ]
4660
+ fn $harness( ) {
4661
+ let src: $src = kani:: any( ) ;
4662
+ let dst: $dst = unsafe { transmute_unchecked_wrapper( src) } ;
4663
+ }
4664
+ } ;
4665
+ }
4666
+
4667
+ //generates harness that transmutes arbitrary values of input type to output type
4668
+ //use when you expect some resulting bit patterns of output type to be invalid
4669
+ macro_rules! transmute_unchecked_should_fail {
4670
+ ( $harness: ident, $src: ty, $dst: ty) => {
4671
+ #[ kani:: proof]
4672
+ #[ kani:: stub_verified( transmute_unchecked_wrapper) ]
4673
+ #[ kani:: should_panic]
4674
+ fn $harness( ) {
4675
+ let src: $src = kani:: any( ) ;
4676
+ let dst: $dst = unsafe { transmute_unchecked_wrapper( src) } ;
4677
+ }
4678
+ } ;
4679
+ }
4680
+
4681
+ //transmute between the 4-byte numerical types
4682
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_i32_to_u32, i32 , u32 ) ;
4683
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_u32_to_i32, u32 , i32 ) ;
4684
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_i32_to_f32, i32 , f32 ) ;
4685
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_f32_to_i32, f32 , i32 ) ;
4686
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_u32_to_f32, u32 , f32 ) ;
4687
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_f32_to_u32, f32 , u32 ) ;
4688
+ //transmute between the 8-byte numerical types
4689
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_i64_to_u64, i64 , u64 ) ;
4690
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_u64_to_i64, u64 , i64 ) ;
4691
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_i64_to_f64, i64 , f64 ) ;
4692
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_f64_to_i64, f64 , i64 ) ;
4693
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_u64_to_f64, u64 , f64 ) ;
4694
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_f64_to_u64, f64 , u64 ) ;
4695
+ //transmute between arrays of bytes and numerical types
4696
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_arr_to_u32, [ u8 ; 4 ] , u32 ) ;
4697
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_u32_to_arr, u32 , [ u8 ; 4 ] ) ;
4698
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_arr_to_u64, [ u8 ; 8 ] , u64 ) ;
4699
+ transmute_unchecked_should_succeed ! ( transmute_unchecked_u64_to_arr, u64 , [ u8 ; 8 ] ) ;
4700
+ //transmute to type with potentially invalid bit patterns
4701
+ transmute_unchecked_should_fail ! ( transmute_unchecked_u8_to_bool, u8 , bool ) ;
4702
+ transmute_unchecked_should_fail ! ( transmute_unchecked_u32_to_char, u32 , char ) ;
4703
+
4704
+ //tests that transmute works correctly when transmuting something with zero size
4705
+ #[ kani:: proof_for_contract( transmute_unchecked_wrapper) ]
4706
+ fn transmute_zero_size ( ) {
4707
+ let empty_arr: [ u8 ; 0 ] = [ ] ;
4708
+ let unit_val: ( ) = unsafe { transmute_unchecked_wrapper ( empty_arr) } ;
4709
+ assert ! ( unit_val == ( ) ) ;
4710
+ }
4711
+
4712
+ //generates harness that transmutes arbitrary values two ways
4713
+ //i.e. (src -> dest) then (dest -> src)
4714
+ //We then check that the output is equal to the input
4715
+ //This tests that transmute does not mutate the bit patterns
4716
+ //Note: this would not catch reversible mutations
4717
+ //e.g., deterministically flipping a bit
4718
+ macro_rules! transmute_unchecked_two_ways {
4719
+ ( $harness: ident, $src: ty, $dst: ty) => {
4720
+ #[ kani:: proof_for_contract( transmute_unchecked_wrapper) ]
4721
+ fn $harness( ) {
4722
+ let src: $src = kani:: any( ) ;
4723
+ let dst: $dst = unsafe { transmute_unchecked_wrapper( src) } ;
4724
+ let src2: $src = unsafe { transmute_unchecked_wrapper( dst) } ;
4725
+ assert_eq!( src, src2) ;
4726
+ }
4727
+ } ;
4728
+ }
4729
+
4730
+ //transmute 2-ways between the 4-byte numerical types
4731
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_i32_to_u32, i32 , u32 ) ;
4732
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_u32_to_i32, u32 , i32 ) ;
4733
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_i32_to_f32, i32 , f32 ) ;
4734
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_u32_to_f32, u32 , f32 ) ;
4735
+ //transmute 2-ways between the 8-byte numerical types
4736
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_i64_to_u64, i64 , u64 ) ;
4737
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_u64_to_i64, u64 , i64 ) ;
4738
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_i64_to_f64, i64 , f64 ) ;
4739
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_u64_to_f64, u64 , f64 ) ;
4740
+ //transmute 2-ways between arrays of bytes and numerical types
4741
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_arr_to_u32, [ u8 ; 4 ] , u32 ) ;
4742
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_u32_to_arr, u32 , [ u8 ; 4 ] ) ;
4743
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_arr_to_u64, [ u8 ; 8 ] , u64 ) ;
4744
+ transmute_unchecked_two_ways ! ( transmute_unchecked_2ways_u64_to_arr, u64 , [ u8 ; 8 ] ) ;
4645
4745
4646
4746
// FIXME: Enable this harness once <https://github.com/model-checking/kani/issues/90> is fixed.
4647
4747
// Harness triggers a spurious failure when writing 0 bytes to an invalid memory location,
0 commit comments