Skip to content

Commit 5bedb1b

Browse files
authored
Merge branch 'main' into update-kani-metrics
2 parents 42cf405 + db8e5a7 commit 5bedb1b

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

doc/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
- [Verification Tools](./tools.md)
1010
- [Kani](./tools/kani.md)
11+
- [GOTO Transcoder](./tools/goto-transcoder.md)
1112

1213
---
1314

library/core/src/intrinsics/mod.rs

+100
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)