Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contracts & Harnesses for unchecked_mul , unchecked_sub, unchecked_shl and unchecked_shr #96

Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
1ae4c6d
Add Kani proofs of unchecked_add for all integer types
Sep 11, 2024
b553678
Format proof files & Add verification function templates
Sep 11, 2024
4db34e4
feat: add i8 uncheck shl verification
MWDZ Sep 11, 2024
54f5507
feat: add i16 and i32 uncheck shl verification
MWDZ Sep 11, 2024
472da0e
added unsafe integer i8 unchecked sub following the template
lanfeima Sep 12, 2024
daaaf7e
Experiment with two verification approaches in mod.rs of core::num
Sep 16, 2024
7bd0e3c
Merge branch 'model-checking:main' into c-0011-core-nums-yenyunw-unsa…
Yenyun035 Sep 18, 2024
1c9dbde
Add contracts to unchecked_add && Add i8::unchecked_add proof
Sep 18, 2024
894231f
Format core::num mod.rs
Sep 18, 2024
2bc4faf
Add comment for unchecked_add proofs
Sep 18, 2024
d9d4b5f
Add harnesses for i16,i32,i64,i128 unchecked_add
Sep 19, 2024
07c8b4a
Add harnesses for u8,u16,u32,u64,u128 unchecked_add
Sep 19, 2024
1fd4c6a
Cleanup misplaced proofs
Sep 19, 2024
b360311
Clean up comment
Sep 20, 2024
8cbca87
Format comment
Sep 20, 2024
0eef858
Remove before contracts. Fix import in
Sep 20, 2024
4858a53
Fix comment
Sep 20, 2024
8ce3381
Merge remote-tracking branch 'origin/c-0011-core-nums-yenyunw-unsafe-…
MWDZ Sep 23, 2024
bbd75f7
unchecked multiplication and shift right
rajathkotyal Sep 23, 2024
483bdf5
Merge branch 'main' into c-0011-core-nums-yenyunw-unsafe-ints
Yenyun035 Sep 23, 2024
71ffd37
Merge branch 'c-0011-core-nums-yenyunw-unsafe-ints' into c-0011-core-…
lanfeima Sep 23, 2024
a7d3cc2
feat: add contract and test case for unchecked_shl in type int and unit
MWDZ Sep 24, 2024
271afad
added preconditions and postconditions
lanfeima Sep 24, 2024
c7762c2
add proof functions for unchecked_sub
lanfeima Sep 24, 2024
ce35002
Merge branch 'model-checking:main' into c-0011-core-nums-yenyunw-unsa…
Yenyun035 Sep 24, 2024
d99844d
Remove ensures contracts && Undo formatting on existing code
Sep 24, 2024
fbcf49e
Add {isize, usize}::unchecked_add harnesses
Sep 24, 2024
864afa6
Small fix typo
rajathkotyal Sep 25, 2024
457a2b5
Merge branch 'model-checking:main' into c-0011-core-nums-yenyunw-unsa…
Yenyun035 Sep 27, 2024
54a03ef
Add harness generation macros for unchecked methods && Update uncheck…
Sep 27, 2024
ae678de
added limits to multiplication proofs, reduced duplicacy in code by u…
rajathkotyal Sep 29, 2024
af6942e
Merge branch 'c-0011-core-nums-yenyunw-unsafe-ints' into c-0011-core-…
rajathkotyal Sep 29, 2024
8ee5682
Remove unused import safety::ensures
Sep 30, 2024
02d706a
unchecked_mul and unchecked_shr proofs (#7)
rajathkotyal Sep 30, 2024
dce9e83
Add comments. Fix spacing
Sep 30, 2024
3880fc7
Revert "Add comments. Fix spacing"
rajathkotyal Oct 2, 2024
781cb87
Revert "unchecked_mul and unchecked_shr proofs (#7)"
rajathkotyal Oct 2, 2024
500e8db
Add comments. Fix spacing
rajathkotyal Oct 2, 2024
1c97825
cleaned up code: deleted the previous attempted proofs
lanfeima Oct 2, 2024
4572831
Merge branch 'c-0011-core-nums-yenyunw-unsafe-ints' into c-0011-core-…
lanfeima Oct 3, 2024
e3eb365
feat: merge the latest version
MWDZ Oct 3, 2024
2b3771f
feat: use macro rules for unchecked_shl harness
MWDZ Oct 3, 2024
1a3bf40
Merge branch 'c-0011-core-nums-junfengj-unchecked-shl' into c-0011-co…
MWDZ Oct 3, 2024
49b0a6b
add interval checks to unchecked_mul
rajathkotyal Oct 5, 2024
7118fa4
Merge branch 'main' into c-0011-core-nums-rajathm-unsafe-ints
rajathkotyal Oct 5, 2024
bbb9656
unchecked neg fix
rajathkotyal Oct 5, 2024
cafeea6
add missing i8, i16 unchecked_mul
rajathkotyal Oct 5, 2024
51745e0
Merge branch 'c-0011-core-nums-rajathm-unsafe-ints' into c-0011-core-…
lanfeima Oct 6, 2024
7f4421c
deleted the postconditions of unchecked_sub
lanfeima Oct 6, 2024
1331a77
deleted the postconditions for the unchecked_sub in uint_macros
lanfeima Oct 6, 2024
c413cac
refacted uncheck_sub harnesses
lanfeima Oct 6, 2024
3dd368e
removed empty submodule
rajathkotyal Oct 7, 2024
da64c78
Merge branch 'main' into c-0011-core-nums-rajathm-unsafe-ints
rajathkotyal Oct 7, 2024
d971f5c
add comments to unchecked_sub
rajathkotyal Oct 7, 2024
50aaf19
Merge branch 'c-0011-core-nums-rajathm-unsafe-ints' of https://github…
rajathkotyal Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions kani
rajathkotyal marked this conversation as resolved.
Show resolved Hide resolved
Submodule kani added at 4f7519
4 changes: 4 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ macro_rules! int_impl {
without modifying the original"]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(!self.overflowing_sub(rhs).1)] // Preconditions: No overflow should occur
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down Expand Up @@ -816,6 +817,7 @@ macro_rules! int_impl {
without modifying the original"]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(!self.overflowing_mul(rhs).1)]
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down Expand Up @@ -1298,6 +1300,7 @@ macro_rules! int_impl {
#[rustc_const_unstable(feature = "unchecked_shifts", issue = "85122")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(rhs < <$ActualT>::BITS)]
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down Expand Up @@ -1424,6 +1427,7 @@ macro_rules! int_impl {
#[rustc_const_unstable(feature = "unchecked_shifts", issue = "85122")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(rhs < <$ActualT>::BITS)] // i.e. requires the right hand side of the shift (rhs) to be less than the number of bits in the type. This prevents undefined behavior.
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down
168 changes: 166 additions & 2 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,7 @@ from_str_radix_size_impl! { i64 isize, u64 usize }
mod verify {
use super::*;

// Verify `unchecked_{add, sub, mul}`
macro_rules! generate_unchecked_math_harness {
($type:ty, $method:ident, $harness_name:ident) => {
#[kani::proof_for_contract($type::$method)]
Expand All @@ -1605,6 +1606,31 @@ mod verify {
}
}

// Improve unchecked_mul performance for {32, 64, 128}-bit integer types
// by adding upper and lower limits for inputs
macro_rules! generate_unchecked_mul_intervals {
($type:ty, $method:ident, $($harness_name:ident, $min:expr, $max:expr),+) => {
$(
#[kani::proof_for_contract($type::$method)]
pub fn $harness_name() {
let num1: $type = kani::any::<$type>();
let num2: $type = kani::any::<$type>();

kani::assume(num1 >= $min && num1 <= $max);
kani::assume(num2 >= $min && num2 <= $max);

// Ensure that multiplication does not overflow
kani::assume(!num1.overflowing_mul(num2).1);

unsafe {
num1.$method(num2);
}
}
)+
}
}

// Verify `unchecked_{shl, shr}`
macro_rules! generate_unchecked_shift_harness {
($type:ty, $method:ident, $harness_name:ident) => {
#[kani::proof_for_contract($type::$method)]
Expand Down Expand Up @@ -1635,10 +1661,11 @@ mod verify {
// `unchecked_add` proofs
//
// Target types:
// i{8,16,32,64,128, size} and u{8,16,32,64,128, size} -- 12 types in total
// i{8,16,32,64,128} and u{8,16,32,64,128} -- 10 types in total
//
// Target contracts:
// #[requires(!self.overflowing_add(rhs).1)]
//#[requires(!self.overflowing_sub(rhs).1)] // Preconditions: No overflow should occur
//#[ensures(|ret| *ret >= Self::MIN && *ret <= Self::MAX)] // Postconditions: Result must be within valid bounds
//
// Target function:
// pub const unsafe fn unchecked_add(self, rhs: Self) -> Self
Expand All @@ -1654,4 +1681,141 @@ mod verify {
generate_unchecked_math_harness!(u64, unchecked_add, checked_unchecked_add_u64);
generate_unchecked_math_harness!(u128, unchecked_add, checked_unchecked_add_u128);
generate_unchecked_math_harness!(usize, unchecked_add, checked_unchecked_add_usize);

// unchecked_mul proofs
//
// Target types:
// i{8,16,32,64,128, size} and u{8,16,32,64,128, size} -- 36 types in total
//
// Target contracts:
// #[requires(!self.overflowing_mul(rhs).1)]
//
// Target function:
// pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self
// exponential state spaces for 32,64 and 128, hence provided limited range for verification.
generate_unchecked_math_harness!(i8, unchecked_mul, checked_unchecked_mul_i8);
generate_unchecked_math_harness!(i16, unchecked_mul, checked_unchecked_mul_i16);

// ====================== i32 Harnesses ======================
generate_unchecked_mul_intervals!(i32, unchecked_mul,
unchecked_mul_i32_small, -10i32, 10i32,
unchecked_mul_i32_large_pos, i32::MAX - 1000i32, i32::MAX,
unchecked_mul_i32_large_neg, i32::MIN, i32::MIN + 1000i32,
unchecked_mul_i32_edge_pos, i32::MAX / 2, i32::MAX,
unchecked_mul_i32_edge_neg, i32::MIN, i32::MIN / 2
);
// ====================== i64 Harnesses ======================
generate_unchecked_mul_intervals!(i64, unchecked_mul,
unchecked_mul_i64_small, -10i64, 10i64,
unchecked_mul_i64_large_pos, i64::MAX - 1000i64, i64::MAX,
unchecked_mul_i64_large_neg, i64::MIN, i64::MIN + 1000i64,
unchecked_mul_i64_edge_pos, i64::MAX / 2, i64::MAX,
unchecked_mul_i64_edge_neg, i64::MIN, i64::MIN / 2
);
// ====================== i128 Harnesses ======================
generate_unchecked_mul_intervals!(i128, unchecked_mul,
unchecked_mul_i128_small, -10i128, 10i128,
unchecked_mul_i128_large_pos, i128::MAX - 1000i128, i128::MAX,
unchecked_mul_i128_large_neg, i128::MIN, i128::MIN + 1000i128,
unchecked_mul_i128_edge_pos, i128::MAX / 2, i128::MAX,
unchecked_mul_i128_edge_neg, i128::MIN, i128::MIN / 2
);
// ====================== isize Harnesses ======================
generate_unchecked_mul_intervals!(isize, unchecked_mul,
unchecked_mul_isize_small, -10isize, 10isize,
unchecked_mul_isize_large_pos, isize::MAX - 1000isize, isize::MAX,
unchecked_mul_isize_large_neg, isize::MIN, isize::MIN + 1000isize,
unchecked_mul_isize_edge_pos, isize::MAX / 2, isize::MAX,
unchecked_mul_isize_edge_neg, isize::MIN, isize::MIN / 2
);

generate_unchecked_math_harness!(u8, unchecked_mul, checked_unchecked_mul_u8);
generate_unchecked_math_harness!(u16, unchecked_mul, checked_unchecked_mul_u16);

// ====================== u32 Harnesses ======================
generate_unchecked_mul_intervals!(u32, unchecked_mul,
unchecked_mul_u32_small, 0u32, 10u32,
unchecked_mul_u32_large, u32::MAX - 1000u32, u32::MAX,
unchecked_mul_u32_edge, u32::MAX / 2, u32::MAX
);
// ====================== u64 Harnesses ======================
generate_unchecked_mul_intervals!(u64, unchecked_mul,
unchecked_mul_u64_small, 0u64, 10u64,
unchecked_mul_u64_large, u64::MAX - 1000u64, u64::MAX,
unchecked_mul_u64_edge, u64::MAX / 2, u64::MAX
);
// ====================== u128 Harnesses ======================
generate_unchecked_mul_intervals!(u128, unchecked_mul,
unchecked_mul_u128_small, 0u128, 10u128,
unchecked_mul_u128_large, u128::MAX - 1000u128, u128::MAX,
unchecked_mul_u128_edge, u128::MAX / 2, u128::MAX
);
// ====================== usize Harnesses ======================
generate_unchecked_mul_intervals!(usize, unchecked_mul,
unchecked_mul_usize_small, 0usize, 10usize,
unchecked_mul_usize_large, usize::MAX - 1000usize, usize::MAX,
unchecked_mul_usize_edge, usize::MAX / 2, usize::MAX
);

// unchecked_shr proofs
//
// Target types:
// i{8,16,32,64,128,size} and u{8,16,32,64,128,size} -- 12 types in total
//
// Target contracts:
// #[requires(rhs < <$ActualT>::BITS)]
//
// Target function:
// pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self
generate_unchecked_shift_harness!(i8, unchecked_shr, checked_unchecked_shr_i8);
generate_unchecked_shift_harness!(i16, unchecked_shr, checked_unchecked_shr_i16);
generate_unchecked_shift_harness!(i32, unchecked_shr, checked_unchecked_shr_i32);
generate_unchecked_shift_harness!(i64, unchecked_shr, checked_unchecked_shr_i64);
generate_unchecked_shift_harness!(i128, unchecked_shr, checked_unchecked_shr_i128);
generate_unchecked_shift_harness!(isize, unchecked_shr, checked_unchecked_shr_isize);
generate_unchecked_shift_harness!(u8, unchecked_shr, checked_unchecked_shr_u8);
generate_unchecked_shift_harness!(u16, unchecked_shr, checked_unchecked_shr_u16);
generate_unchecked_shift_harness!(u32, unchecked_shr, checked_unchecked_shr_u32);
generate_unchecked_shift_harness!(u64, unchecked_shr, checked_unchecked_shr_u64);
generate_unchecked_shift_harness!(u128, unchecked_shr, checked_unchecked_shr_u128);
generate_unchecked_shift_harness!(usize, unchecked_shr, checked_unchecked_shr_usize);

// `unchecked_shl` proofs
//
// Target types:
// i{8,16,32,64,128} and u{8,16,32,64,128} -- 12 types in total
//
// Target contracts:
// #[requires(shift < Self::BITS)]
// #[ensures(|ret| *ret == self << shift)]
//
// Target function:
// pub const unsafe fn unchecked_shl(self, shift: u32) -> Self
//
// This function performs an unchecked bitwise left shift operation.
generate_unchecked_shift_harness!(i8, unchecked_shl, checked_unchecked_shl_i8);
generate_unchecked_shift_harness!(i16, unchecked_shl, checked_unchecked_shl_i16);
generate_unchecked_shift_harness!(i32, unchecked_shl, checked_unchecked_shl_i32);
generate_unchecked_shift_harness!(i64, unchecked_shl, checked_unchecked_shl_i64);
generate_unchecked_shift_harness!(i128, unchecked_shl, checked_unchecked_shl_i128);
generate_unchecked_shift_harness!(isize, unchecked_shl, checked_unchecked_shl_isize);
generate_unchecked_shift_harness!(u8, unchecked_shl, checked_unchecked_shl_u8);
generate_unchecked_shift_harness!(u16, unchecked_shl, checked_unchecked_shl_u16);
generate_unchecked_shift_harness!(u32, unchecked_shl, checked_unchecked_shl_u32);
generate_unchecked_shift_harness!(u64, unchecked_shl, checked_unchecked_shl_u64);
generate_unchecked_shift_harness!(u128, unchecked_shl, checked_unchecked_shl_u128);
generate_unchecked_shift_harness!(usize, unchecked_shl, checked_unchecked_shl_usize);

generate_unchecked_math_harness!(i8, unchecked_sub, checked_unchecked_sub_i8);
generate_unchecked_math_harness!(i16, unchecked_sub, checked_unchecked_sub_i16);
generate_unchecked_math_harness!(i32, unchecked_sub, checked_unchecked_sub_i32);
generate_unchecked_math_harness!(i64, unchecked_sub, checked_unchecked_sub_i64);
generate_unchecked_math_harness!(i128, unchecked_sub, checked_unchecked_sub_i128);
generate_unchecked_math_harness!(isize, unchecked_sub, checked_unchecked_sub_isize);
generate_unchecked_math_harness!(u8, unchecked_sub, checked_unchecked_sub_u8);
generate_unchecked_math_harness!(u16, unchecked_sub, checked_unchecked_sub_u16);
generate_unchecked_math_harness!(u32, unchecked_sub, checked_unchecked_sub_u32);
generate_unchecked_math_harness!(u64, unchecked_sub, checked_unchecked_sub_u64);
generate_unchecked_math_harness!(u128, unchecked_sub, checked_unchecked_sub_u128);
generate_unchecked_math_harness!(usize, unchecked_sub, checked_unchecked_sub_usize);
}
4 changes: 4 additions & 0 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(!self.overflowing_sub(rhs).1)] // Preconditions: No overflow should occur
pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down Expand Up @@ -908,6 +909,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(!self.overflowing_mul(rhs).1)]
pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down Expand Up @@ -1487,6 +1489,7 @@ macro_rules! uint_impl {
#[rustc_const_unstable(feature = "unchecked_shifts", issue = "85122")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(rhs < <$ActualT>::BITS)]
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down Expand Up @@ -1613,6 +1616,7 @@ macro_rules! uint_impl {
#[rustc_const_unstable(feature = "unchecked_shifts", issue = "85122")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[requires(rhs < <$ActualT>::BITS)]// i.e. requires the right hand side of the shift (rhs) to be less than the number of bits in the type. This prevents undefined behavior.
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
assert_unsafe_precondition!(
check_language_ub,
Expand Down
Loading