Skip to content

Commit 8a0d0ce

Browse files
authored
Contracts and Harnesses for core::ptr::byte_offset_from (#186)
1 parent d92a7ea commit 8a0d0ce

File tree

2 files changed

+407
-3
lines changed

2 files changed

+407
-3
lines changed

library/core/src/ptr/const_ptr.rs

+203-2
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,16 @@ impl<T: ?Sized> *const T {
730730
#[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
731731
#[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
732732
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
733+
#[requires(
734+
(mem::size_of_val_raw(self) != 0) &&
735+
// Ensures subtracting `origin` from `self` doesn't overflow
736+
(self.addr() as isize).checked_sub(origin.addr() as isize).is_some() &&
737+
// Ensure both pointers are in the same allocation or are pointing to the same address
738+
(self.addr() == origin.addr() ||
739+
core::ub_checks::same_allocation(self as *const u8, origin as *const u8))
740+
)]
741+
// The result should equal the distance in terms of bytes
742+
#[ensures(|result| *result == (self.addr() as isize - origin.addr() as isize))]
733743
pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize {
734744
// SAFETY: the caller must uphold the safety contract for `offset_from`.
735745
unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) }
@@ -1940,7 +1950,7 @@ mod verify {
19401950
check_const_offset_usize
19411951
);
19421952

1943-
// Generte harnesses for composite types (add, sub, offset)
1953+
// Generate harnesses for composite types (add, sub, offset)
19441954
generate_arithmetic_harnesses!(
19451955
(i8, i8),
19461956
check_const_add_tuple_1,
@@ -2116,6 +2126,17 @@ mod verify {
21162126
// PointerGenerator does not support dynamic sized arrays.
21172127
const ARRAY_LEN: usize = 40;
21182128

2129+
#[kani::proof]
2130+
pub fn check_const_byte_offset_from_fixed_offset() {
2131+
let arr: [u32; ARRAY_LEN] = kani::Arbitrary::any_array();
2132+
let offset: usize = kani::any_where(|&x| x <= ARRAY_LEN);
2133+
let origin_ptr: *const u32 = arr.as_ptr();
2134+
let self_ptr: *const u32 = unsafe { origin_ptr.byte_offset(offset as isize) };
2135+
let result: isize = unsafe { self_ptr.byte_offset_from(origin_ptr) };
2136+
assert_eq!(result, offset as isize);
2137+
assert_eq!(result, (self_ptr.addr() as isize - origin_ptr.addr() as isize));
2138+
}
2139+
21192140
macro_rules! generate_offset_from_harness {
21202141
($type: ty, $proof_name1: ident, $proof_name2: ident) => {
21212142
// Proof for a single element
@@ -2156,7 +2177,7 @@ mod verify {
21562177
};
21572178
}
21582179

2159-
// Proof for unit size will panic as offset_from needs the pointee size to be greater then 0
2180+
// Proof for unit size will panic as offset_from needs the pointee size to be greater than 0
21602181
#[kani::proof_for_contract(<*const ()>::offset_from)]
21612182
#[kani::should_panic]
21622183
pub fn check_const_offset_from_unit() {
@@ -2252,6 +2273,186 @@ mod verify {
22522273
check_const_offset_from_tuple_4_arr
22532274
);
22542275

2276+
// Proof for contact of byte_offset_from to verify unit type
2277+
#[kani::proof_for_contract(<*const ()>::byte_offset_from)]
2278+
pub fn check_const_byte_offset_from_unit() {
2279+
let val: () = ();
2280+
let src_ptr: *const () = &val;
2281+
let dest_ptr: *const () = &val;
2282+
unsafe {
2283+
dest_ptr.byte_offset_from(src_ptr);
2284+
}
2285+
}
2286+
2287+
// generate proofs for contracts for byte_offset_from to verify int and composite
2288+
// types
2289+
// - `$type`: pointee type
2290+
// - `$proof_name1`: name of the harness for single element
2291+
// - `$proof_name2`: name of the harness for array of elements
2292+
macro_rules! generate_const_byte_offset_from_harness {
2293+
($type: ty, $proof_name1: ident, $proof_name2: ident) => {
2294+
// Proof for a single element
2295+
#[kani::proof_for_contract(<*const $type>::byte_offset_from)]
2296+
pub fn $proof_name1() {
2297+
const gen_size: usize = mem::size_of::<$type>();
2298+
let mut generator1 = PointerGenerator::<gen_size>::new();
2299+
let mut generator2 = PointerGenerator::<gen_size>::new();
2300+
let ptr1: *const $type = generator1.any_in_bounds().ptr;
2301+
let ptr2: *const $type = if kani::any() {
2302+
generator1.any_alloc_status().ptr
2303+
} else {
2304+
generator2.any_alloc_status().ptr
2305+
};
2306+
2307+
unsafe {
2308+
ptr1.byte_offset_from(ptr2);
2309+
}
2310+
}
2311+
2312+
// Proof for large arrays
2313+
#[kani::proof_for_contract(<*const $type>::byte_offset_from)]
2314+
pub fn $proof_name2() {
2315+
const gen_size: usize = mem::size_of::<$type>();
2316+
let mut generator1 = PointerGenerator::<{ gen_size * ARRAY_LEN }>::new();
2317+
let mut generator2 = PointerGenerator::<{ gen_size * ARRAY_LEN }>::new();
2318+
let ptr1: *const $type = generator1.any_in_bounds().ptr;
2319+
let ptr2: *const $type = if kani::any() {
2320+
generator1.any_alloc_status().ptr
2321+
} else {
2322+
generator2.any_alloc_status().ptr
2323+
};
2324+
2325+
unsafe {
2326+
ptr1.byte_offset_from(ptr2);
2327+
}
2328+
}
2329+
};
2330+
}
2331+
2332+
generate_const_byte_offset_from_harness!(
2333+
u8,
2334+
check_const_byte_offset_from_u8,
2335+
check_const_byte_offset_from_u8_arr
2336+
);
2337+
generate_const_byte_offset_from_harness!(
2338+
u16,
2339+
check_const_byte_offset_from_u16,
2340+
check_const_byte_offset_from_u16_arr
2341+
);
2342+
generate_const_byte_offset_from_harness!(
2343+
u32,
2344+
check_const_byte_offset_from_u32,
2345+
check_const_byte_offset_from_u32_arr
2346+
);
2347+
generate_const_byte_offset_from_harness!(
2348+
u64,
2349+
check_const_byte_offset_from_u64,
2350+
check_const_byte_offset_from_u64_arr
2351+
);
2352+
generate_const_byte_offset_from_harness!(
2353+
u128,
2354+
check_const_byte_offset_from_u128,
2355+
check_const_byte_offset_from_u128_arr
2356+
);
2357+
generate_const_byte_offset_from_harness!(
2358+
usize,
2359+
check_const_byte_offset_from_usize,
2360+
check_const_byte_offset_from_usize_arr
2361+
);
2362+
2363+
generate_const_byte_offset_from_harness!(
2364+
i8,
2365+
check_const_byte_offset_from_i8,
2366+
check_const_byte_offset_from_i8_arr
2367+
);
2368+
generate_const_byte_offset_from_harness!(
2369+
i16,
2370+
check_const_byte_offset_from_i16,
2371+
check_const_byte_offset_from_i16_arr
2372+
);
2373+
generate_const_byte_offset_from_harness!(
2374+
i32,
2375+
check_const_byte_offset_from_i32,
2376+
check_const_byte_offset_from_i32_arr
2377+
);
2378+
generate_const_byte_offset_from_harness!(
2379+
i64,
2380+
check_const_byte_offset_from_i64,
2381+
check_const_byte_offset_from_i64_arr
2382+
);
2383+
generate_const_byte_offset_from_harness!(
2384+
i128,
2385+
check_const_byte_offset_from_i128,
2386+
check_const_byte_offset_from_i128_arr
2387+
);
2388+
generate_const_byte_offset_from_harness!(
2389+
isize,
2390+
check_const_byte_offset_from_isize,
2391+
check_const_byte_offset_from_isize_arr
2392+
);
2393+
2394+
generate_const_byte_offset_from_harness!(
2395+
(i8, i8),
2396+
check_const_byte_offset_from_tuple_1,
2397+
check_const_byte_offset_from_tuple_1_arr
2398+
);
2399+
generate_const_byte_offset_from_harness!(
2400+
(f64, bool),
2401+
check_const_byte_offset_from_tuple_2,
2402+
check_const_byte_offset_from_tuple_2_arr
2403+
);
2404+
generate_const_byte_offset_from_harness!(
2405+
(u32, i16, f32),
2406+
check_const_byte_offset_from_tuple_3,
2407+
check_const_byte_offset_from_tuple_3_arr
2408+
);
2409+
generate_const_byte_offset_from_harness!(
2410+
((), bool, u8, u16, i32, f64, i128, usize),
2411+
check_const_byte_offset_from_tuple_4,
2412+
check_const_byte_offset_from_tuple_4_arr
2413+
);
2414+
2415+
// length of the slice generated from PointerGenerator
2416+
const SLICE_LEN: usize = 10;
2417+
2418+
// generate proofs for contracts for byte_offset_from to verify slices
2419+
// - `$type`: type of the underlyign element within the slice pointer
2420+
// - `$proof_name`: name of the harness
2421+
macro_rules! generate_const_byte_offset_from_slice_harness {
2422+
($type: ty, $proof_name: ident) => {
2423+
#[kani::proof_for_contract(<*const [$type]>::byte_offset_from)]
2424+
pub fn $proof_name() {
2425+
const gen_size: usize = mem::size_of::<$type>();
2426+
let mut generator1 = PointerGenerator::<{ gen_size * ARRAY_LEN }>::new();
2427+
let mut generator2 = PointerGenerator::<{ gen_size * ARRAY_LEN }>::new();
2428+
let ptr1: *const [$type] =
2429+
generator1.any_in_bounds().ptr as *const [$type; SLICE_LEN];
2430+
let ptr2: *const [$type] = if kani::any() {
2431+
generator1.any_alloc_status().ptr as *const [$type; SLICE_LEN]
2432+
} else {
2433+
generator2.any_alloc_status().ptr as *const [$type; SLICE_LEN]
2434+
};
2435+
2436+
unsafe {
2437+
ptr1.byte_offset_from(ptr2);
2438+
}
2439+
}
2440+
};
2441+
}
2442+
2443+
generate_const_byte_offset_from_slice_harness!(u8, check_const_byte_offset_from_u8_slice);
2444+
generate_const_byte_offset_from_slice_harness!(u16, check_const_byte_offset_from_u16_slice);
2445+
generate_const_byte_offset_from_slice_harness!(u32, check_const_byte_offset_from_u32_slice);
2446+
generate_const_byte_offset_from_slice_harness!(u64, check_const_byte_offset_from_u64_slice);
2447+
generate_const_byte_offset_from_slice_harness!(u128, check_const_byte_offset_from_u128_slice);
2448+
generate_const_byte_offset_from_slice_harness!(usize, check_const_byte_offset_from_usize_slice);
2449+
generate_const_byte_offset_from_slice_harness!(i8, check_const_byte_offset_from_i8_slice);
2450+
generate_const_byte_offset_from_slice_harness!(i16, check_const_byte_offset_from_i16_slice);
2451+
generate_const_byte_offset_from_slice_harness!(i32, check_const_byte_offset_from_i32_slice);
2452+
generate_const_byte_offset_from_slice_harness!(i64, check_const_byte_offset_from_i64_slice);
2453+
generate_const_byte_offset_from_slice_harness!(i128, check_const_byte_offset_from_i128_slice);
2454+
generate_const_byte_offset_from_slice_harness!(isize, check_const_byte_offset_from_isize_slice);
2455+
22552456
#[kani::proof_for_contract(<*const ()>::byte_offset)]
22562457
#[kani::should_panic]
22572458
pub fn check_const_byte_offset_unit_invalid_count() {

0 commit comments

Comments
 (0)