Skip to content

Commit 2338dad

Browse files
authored
Refactor Contracts and Harnesses for <*mut T>::add, sub and offset (#203)
**Summary** This PR synchronizes updates from PR #166 and applies them to `mut` function contracts and proof for contracts.
1 parent 72323e4 commit 2338dad

File tree

1 file changed

+146
-118
lines changed

1 file changed

+146
-118
lines changed

library/core/src/ptr/mut_ptr.rs

+146-118
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,11 @@ impl<T: ?Sized> *mut T {
405405
// Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
406406
// These conditions are not verified as part of the preconditions.
407407
#[requires(
408-
// Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
409-
count.checked_mul(core::mem::size_of::<T>() as isize).is_some() &&
410-
// Precondition 2: adding the computed offset to `self` does not cause overflow
411-
(self as isize).checked_add((count * core::mem::size_of::<T>() as isize)).is_some() &&
408+
// Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`.
409+
// Precondition 2: adding the computed offset to `self` does not cause overflow.
410+
// These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani.
411+
count.checked_mul(core::mem::size_of::<T>() as isize)
412+
.map_or(false, |computed_offset| (self as isize).checked_add(computed_offset).is_some()) &&
412413
// Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
413414
// Otherwise, for non-unit types, `self` and `self.wrapping_offset(count)` should point to the same allocated object,
414415
// restricting `count` to prevent crossing allocation boundaries.
@@ -1016,11 +1017,13 @@ impl<T: ?Sized> *mut T {
10161017
// Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
10171018
// These conditions are not verified as part of the preconditions.
10181019
#[requires(
1019-
// Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
1020-
count.checked_mul(core::mem::size_of::<T>()).is_some() &&
1021-
count * core::mem::size_of::<T>() <= isize::MAX as usize &&
1022-
// Precondition 2: adding the computed offset to `self` does not cause overflow
1023-
(self as isize).checked_add((count * core::mem::size_of::<T>()) as isize).is_some() &&
1020+
// Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`.
1021+
// Precondition 2: adding the computed offset to `self` does not cause overflow.
1022+
// These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani.
1023+
count.checked_mul(core::mem::size_of::<T>())
1024+
.map_or(false, |computed_offset| {
1025+
computed_offset <= isize::MAX as usize && (self as isize).checked_add(computed_offset as isize).is_some()
1026+
}) &&
10241027
// Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
10251028
// Otherwise, for non-unit types, `self` and `self.wrapping_add(count)` should point to the same allocated object,
10261029
// restricting `count` to prevent crossing allocation boundaries.
@@ -1140,11 +1143,13 @@ impl<T: ?Sized> *mut T {
11401143
// Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
11411144
// These conditions are not verified as part of the preconditions.
11421145
#[requires(
1143-
// Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
1144-
count.checked_mul(core::mem::size_of::<T>()).is_some() &&
1145-
count * core::mem::size_of::<T>() <= isize::MAX as usize &&
1146-
// Precondition 2: subtracting the computed offset from `self` does not cause overflow
1147-
(self as isize).checked_sub((count * core::mem::size_of::<T>()) as isize).is_some() &&
1146+
// Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`.
1147+
// Precondition 2: substracting the computed offset from `self` does not cause overflow.
1148+
// These two preconditions are combined for performance reason, as multiplication is computationally expensive in Kani.
1149+
count.checked_mul(core::mem::size_of::<T>())
1150+
.map_or(false, |computed_offset| {
1151+
computed_offset <= isize::MAX as usize && (self as isize).checked_sub(computed_offset as isize).is_some()
1152+
}) &&
11481153
// Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
11491154
// Otherwise, for non-unit types, `self` and `self.wrapping_sub(count)` should point to the same allocated object,
11501155
// restricting `count` to prevent crossing allocation boundaries.
@@ -2173,120 +2178,143 @@ impl<T: ?Sized> PartialOrd for *mut T {
21732178
mod verify {
21742179
use crate::kani;
21752180

2176-
/// This macro generates proofs for contracts on `add`, `sub`, and `offset`
2177-
/// operations for pointers to integer, composite, and unit types.
2178-
/// - `$type`: Specifies the pointee type.
2179-
/// - `$proof_name`: Specifies the name of the generated proof for contract.
2180-
macro_rules! generate_mut_arithmetic_harness {
2181-
($type:ty, $proof_name:ident, add) => {
2182-
#[kani::proof_for_contract(<*mut $type>::add)]
2181+
/// This macro generates a single verification harness for the `offset`, `add`, or `sub`
2182+
/// pointer operations, supporting integer, composite, or unit types.
2183+
/// - `$ty`: The type of the slice's elements (e.g., `i32`, `u32`, tuples).
2184+
/// - `$fn_name`: The name of the function being checked (`add`, `sub`, or `offset`).
2185+
/// - `$proof_name`: The name assigned to the generated proof for the contract.
2186+
/// - `$count_ty:ty`: The type of the input variable passed to the method being invoked.
2187+
///
2188+
/// Note: This macro is intended for internal use only and should be invoked exclusively
2189+
/// by the `generate_arithmetic_harnesses` macro. Its purpose is to reduce code duplication,
2190+
/// and it is not meant to be used directly elsewhere in the codebase.
2191+
macro_rules! generate_single_arithmetic_harness {
2192+
($ty:ty, $proof_name:ident, $fn_name:ident, $count_ty:ty) => {
2193+
#[kani::proof_for_contract(<*mut $ty>::$fn_name)]
21832194
pub fn $proof_name() {
21842195
// 200 bytes are large enough to cover all pointee types used for testing
21852196
const BUF_SIZE: usize = 200;
21862197
let mut generator = kani::PointerGenerator::<BUF_SIZE>::new();
2187-
let test_ptr: *mut $type = generator.any_in_bounds().ptr;
2188-
let count: usize = kani::any();
2198+
let test_ptr: *mut $ty = generator.any_in_bounds().ptr;
2199+
let count: $count_ty = kani::any();
21892200
unsafe {
2190-
test_ptr.add(count);
2201+
test_ptr.$fn_name(count);
21912202
}
21922203
}
21932204
};
2194-
($type:ty, $proof_name:ident, sub) => {
2195-
#[kani::proof_for_contract(<*mut $type>::sub)]
2196-
pub fn $proof_name() {
2197-
// 200 bytes are large enough to cover all pointee types used for testing
2198-
const BUF_SIZE: usize = 200;
2199-
let mut generator = kani::PointerGenerator::<BUF_SIZE>::new();
2200-
let test_ptr: *mut $type = generator.any_in_bounds().ptr;
2201-
let count: usize = kani::any();
2202-
unsafe {
2203-
test_ptr.sub(count);
2204-
}
2205-
}
2206-
};
2207-
($type:ty, $proof_name:ident, offset) => {
2208-
#[kani::proof_for_contract(<*mut $type>::offset)]
2209-
pub fn $proof_name() {
2210-
// 200 bytes are large enough to cover all pointee types used for testing
2211-
const BUF_SIZE: usize = 200;
2212-
let mut generator = kani::PointerGenerator::<BUF_SIZE>::new();
2213-
let test_ptr: *mut $type = generator.any_in_bounds().ptr;
2214-
let count: isize = kani::any();
2215-
unsafe {
2216-
test_ptr.offset(count);
2217-
}
2218-
}
2205+
}
2206+
2207+
/// This macro generates verification harnesses for the `offset`, `add`, and `sub`
2208+
/// pointer operations, supporting integer, composite, and unit types.
2209+
/// - `$ty`: The pointee type (e.g., i32, u32, tuples).
2210+
/// - `$offset_fn_name`: The name for the `offset` proof for contract.
2211+
/// - `$add_fn_name`: The name for the `add` proof for contract.
2212+
/// - `$sub_fn_name`: The name for the `sub` proof for contract.
2213+
macro_rules! generate_arithmetic_harnesses {
2214+
($ty:ty, $add_fn_name:ident, $sub_fn_name:ident, $offset_fn_name:ident) => {
2215+
generate_single_arithmetic_harness!($ty, $add_fn_name, add, usize);
2216+
generate_single_arithmetic_harness!($ty, $sub_fn_name, sub, usize);
2217+
generate_single_arithmetic_harness!($ty, $offset_fn_name, offset, isize);
22192218
};
22202219
}
22212220

2222-
// <*mut T>:: add() integer types verification
2223-
generate_mut_arithmetic_harness!(i8, check_mut_add_i8, add);
2224-
generate_mut_arithmetic_harness!(i16, check_mut_add_i16, add);
2225-
generate_mut_arithmetic_harness!(i32, check_mut_add_i32, add);
2226-
generate_mut_arithmetic_harness!(i64, check_mut_add_i64, add);
2227-
generate_mut_arithmetic_harness!(i128, check_mut_add_i128, add);
2228-
generate_mut_arithmetic_harness!(isize, check_mut_add_isize, add);
2229-
// Due to a bug of kani this test case is malfunctioning for now.
2221+
// Generate harnesses for unit type (add, sub, offset)
2222+
generate_arithmetic_harnesses!(
2223+
(),
2224+
check_mut_add_unit,
2225+
check_mut_sub_unit,
2226+
check_mut_offset_unit
2227+
);
2228+
2229+
// Generate harnesses for integer types (add, sub, offset)
2230+
generate_arithmetic_harnesses!(i8, check_mut_add_i8, check_mut_sub_i8, check_mut_offset_i8);
2231+
generate_arithmetic_harnesses!(
2232+
i16,
2233+
check_mut_add_i16,
2234+
check_mut_sub_i16,
2235+
check_mut_offset_i16
2236+
);
2237+
generate_arithmetic_harnesses!(
2238+
i32,
2239+
check_mut_add_i32,
2240+
check_mut_sub_i32,
2241+
check_mut_offset_i32
2242+
);
2243+
generate_arithmetic_harnesses!(
2244+
i64,
2245+
check_mut_add_i64,
2246+
check_mut_sub_i64,
2247+
check_mut_offset_i64
2248+
);
2249+
generate_arithmetic_harnesses!(
2250+
i128,
2251+
check_mut_add_i128,
2252+
check_mut_sub_i128,
2253+
check_mut_offset_i128
2254+
);
2255+
generate_arithmetic_harnesses!(
2256+
isize,
2257+
check_mut_add_isize,
2258+
check_mut_sub_isize,
2259+
check_mut_offset_isize
2260+
);
2261+
// Due to a bug of kani the test `check_mut_add_u8` is malfunctioning for now.
22302262
// Tracking issue: https://github.com/model-checking/kani/issues/3743
2231-
// generate_mut_arithmetic_harness!(u8, check_mut_add_u8, add);
2232-
generate_mut_arithmetic_harness!(u16, check_mut_add_u16, add);
2233-
generate_mut_arithmetic_harness!(u32, check_mut_add_u32, add);
2234-
generate_mut_arithmetic_harness!(u64, check_mut_add_u64, add);
2235-
generate_mut_arithmetic_harness!(u128, check_mut_add_u128, add);
2236-
generate_mut_arithmetic_harness!(usize, check_mut_add_usize, add);
2237-
2238-
// <*mut T>:: add() unit type verification
2239-
generate_mut_arithmetic_harness!((), check_mut_add_unit, add);
2240-
2241-
// <*mut T>:: add() composite types verification
2242-
generate_mut_arithmetic_harness!((i8, i8), check_mut_add_tuple_1, add);
2243-
generate_mut_arithmetic_harness!((f64, bool), check_mut_add_tuple_2, add);
2244-
generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_add_tuple_3, add);
2245-
generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_add_tuple_4, add);
2246-
2247-
// <*mut T>:: sub() integer types verification
2248-
generate_mut_arithmetic_harness!(i8, check_mut_sub_i8, sub);
2249-
generate_mut_arithmetic_harness!(i16, check_mut_sub_i16, sub);
2250-
generate_mut_arithmetic_harness!(i32, check_mut_sub_i32, sub);
2251-
generate_mut_arithmetic_harness!(i64, check_mut_sub_i64, sub);
2252-
generate_mut_arithmetic_harness!(i128, check_mut_sub_i128, sub);
2253-
generate_mut_arithmetic_harness!(isize, check_mut_sub_isize, sub);
2254-
generate_mut_arithmetic_harness!(u8, check_mut_sub_u8, sub);
2255-
generate_mut_arithmetic_harness!(u16, check_mut_sub_u16, sub);
2256-
generate_mut_arithmetic_harness!(u32, check_mut_sub_u32, sub);
2257-
generate_mut_arithmetic_harness!(u64, check_mut_sub_u64, sub);
2258-
generate_mut_arithmetic_harness!(u128, check_mut_sub_u128, sub);
2259-
generate_mut_arithmetic_harness!(usize, check_mut_sub_usize, sub);
2260-
2261-
// <*mut T>:: sub() unit type verification
2262-
generate_mut_arithmetic_harness!((), check_mut_sub_unit, sub);
2263-
2264-
// <*mut T>:: sub() composite types verification
2265-
generate_mut_arithmetic_harness!((i8, i8), check_mut_sub_tuple_1, sub);
2266-
generate_mut_arithmetic_harness!((f64, bool), check_mut_sub_tuple_2, sub);
2267-
generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_sub_tuple_3, sub);
2268-
generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_sub_tuple_4, sub);
2269-
2270-
// fn <*mut T>::offset() integer types verification
2271-
generate_mut_arithmetic_harness!(i8, check_mut_offset_i8, offset);
2272-
generate_mut_arithmetic_harness!(i16, check_mut_offset_i16, offset);
2273-
generate_mut_arithmetic_harness!(i32, check_mut_offset_i32, offset);
2274-
generate_mut_arithmetic_harness!(i64, check_mut_offset_i64, offset);
2275-
generate_mut_arithmetic_harness!(i128, check_mut_offset_i128, offset);
2276-
generate_mut_arithmetic_harness!(isize, check_mut_offset_isize, offset);
2277-
generate_mut_arithmetic_harness!(u8, check_mut_offset_u8, offset);
2278-
generate_mut_arithmetic_harness!(u16, check_mut_offset_u16, offset);
2279-
generate_mut_arithmetic_harness!(u32, check_mut_offset_u32, offset);
2280-
generate_mut_arithmetic_harness!(u64, check_mut_offset_u64, offset);
2281-
generate_mut_arithmetic_harness!(u128, check_mut_offset_u128, offset);
2282-
generate_mut_arithmetic_harness!(usize, check_mut_offset_usize, offset);
2283-
2284-
// fn <*mut T>::offset() unit type verification
2285-
generate_mut_arithmetic_harness!((), check_mut_offset_unit, offset);
2286-
2287-
// fn <*mut T>::offset() composite type verification
2288-
generate_mut_arithmetic_harness!((i8, i8), check_mut_offset_tuple_1, offset);
2289-
generate_mut_arithmetic_harness!((f64, bool), check_mut_offset_tuple_2, offset);
2290-
generate_mut_arithmetic_harness!((i32, f64, bool), check_mut_offset_tuple_3, offset);
2291-
generate_mut_arithmetic_harness!((i8, u16, i32, u64, isize), check_mut_offset_tuple_4, offset);
2263+
// generate_arithmetic_harnesses!(u8, check_mut_add_u8, check_mut_sub_u8, check_mut_offset_u8);
2264+
generate_arithmetic_harnesses!(
2265+
u16,
2266+
check_mut_add_u16,
2267+
check_mut_sub_u16,
2268+
check_mut_offset_u16
2269+
);
2270+
generate_arithmetic_harnesses!(
2271+
u32,
2272+
check_mut_add_u32,
2273+
check_mut_sub_u32,
2274+
check_mut_offset_u32
2275+
);
2276+
generate_arithmetic_harnesses!(
2277+
u64,
2278+
check_mut_add_u64,
2279+
check_mut_sub_u64,
2280+
check_mut_offset_u64
2281+
);
2282+
generate_arithmetic_harnesses!(
2283+
u128,
2284+
check_mut_add_u128,
2285+
check_mut_sub_u128,
2286+
check_mut_offset_u128
2287+
);
2288+
generate_arithmetic_harnesses!(
2289+
usize,
2290+
check_mut_add_usize,
2291+
check_mut_sub_usize,
2292+
check_mut_offset_usize
2293+
);
2294+
2295+
// Generte harnesses for composite types (add, sub, offset)
2296+
generate_arithmetic_harnesses!(
2297+
(i8, i8),
2298+
check_mut_add_tuple_1,
2299+
check_mut_sub_tuple_1,
2300+
check_mut_offset_tuple_1
2301+
);
2302+
generate_arithmetic_harnesses!(
2303+
(f64, bool),
2304+
check_mut_add_tuple_2,
2305+
check_mut_sub_tuple_2,
2306+
check_mut_offset_tuple_2
2307+
);
2308+
generate_arithmetic_harnesses!(
2309+
(i32, f64, bool),
2310+
check_mut_add_tuple_3,
2311+
check_mut_sub_tuple_3,
2312+
check_mut_offset_tuple_3
2313+
);
2314+
generate_arithmetic_harnesses!(
2315+
(i8, u16, i32, u64, isize),
2316+
check_mut_add_tuple_4,
2317+
check_mut_sub_tuple_4,
2318+
check_mut_offset_tuple_4
2319+
);
22922320
}

0 commit comments

Comments
 (0)