@@ -4642,6 +4642,106 @@ mod verify {
46424642 let dst = if kani:: any ( ) { gen_any_ptr ( & mut buffer2) } else { gen_any_ptr ( & mut buffer1) } ;
46434643 unsafe { copy_nonoverlapping ( src, dst, kani:: any ( ) ) }
46444644 }
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 ] ) ;
46454745
46464746 // FIXME: Enable this harness once <https://github.com/model-checking/kani/issues/90> is fixed.
46474747 // Harness triggers a spurious failure when writing 0 bytes to an invalid memory location,
0 commit comments