Skip to content

Commit 79498aa

Browse files
tautschnigaa-lunaSahithiMVMooniniteErrcarolynzech
authored
NonZero (unchecked_mul & unchecked_add) Proof for Contracts (#338)
Towards #71 These are the changes contributed by [SahithiMV](https://github.com/SahithiMV) in #184 plus the proposed changes in that PR. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: aaluna <[email protected]> Co-authored-by: SahithiMV <[email protected]> Co-authored-by: aaluna <[email protected]> Co-authored-by: Carolyn Zech <[email protected]> Co-authored-by: Zyad Hassan <[email protected]> Co-authored-by: Carolyn Zech <[email protected]>
1 parent 7dd01bb commit 79498aa

File tree

1 file changed

+315
-0
lines changed

1 file changed

+315
-0
lines changed

library/core/src/num/nonzero.rs

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,12 @@ macro_rules! nonzero_integer {
11121112
#[must_use = "this returns the result of the operation, \
11131113
without modifying the original"]
11141114
#[inline]
1115+
#[requires({
1116+
self.get().checked_mul(other.get()).is_some()
1117+
})]
1118+
#[ensures(|result: &Self| {
1119+
self.get().checked_mul(other.get()).is_some_and(|product| product == result.get())
1120+
})]
11151121
pub const unsafe fn unchecked_mul(self, other: Self) -> Self {
11161122
// SAFETY: The caller ensures there is no overflow.
11171123
unsafe { Self::new_unchecked(self.get().unchecked_mul(other.get())) }
@@ -1514,6 +1520,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
15141520
#[must_use = "this returns the result of the operation, \
15151521
without modifying the original"]
15161522
#[inline]
1523+
#[requires({
1524+
self.get().checked_add(other).is_some()
1525+
})]
1526+
#[ensures(|result: &Self| {
1527+
// Postcondition: the result matches the expected addition
1528+
self.get().checked_add(other).is_some_and(|sum| sum == result.get())
1529+
})]
15171530
pub const unsafe fn unchecked_add(self, other: $Int) -> Self {
15181531
// SAFETY: The caller ensures there is no overflow.
15191532
unsafe { Self::new_unchecked(self.get().unchecked_add(other)) }
@@ -2575,4 +2588,306 @@ mod verify {
25752588
nonzero_check_clamp_panic!(core::num::NonZeroU64, nonzero_check_clamp_panic_for_u64);
25762589
nonzero_check_clamp_panic!(core::num::NonZeroU128, nonzero_check_clamp_panic_for_u128);
25772590
nonzero_check_clamp_panic!(core::num::NonZeroUsize, nonzero_check_clamp_panic_for_usize);
2591+
2592+
macro_rules! check_mul_unchecked_small {
2593+
($t:ty, $nonzero_type:ty, $nonzero_check_unchecked_mul_for:ident) => {
2594+
#[kani::proof_for_contract(NonZero::<$t>::unchecked_mul)]
2595+
pub fn $nonzero_check_unchecked_mul_for() {
2596+
let x: $nonzero_type = kani::any();
2597+
let y: $nonzero_type = kani::any();
2598+
2599+
unsafe {
2600+
x.unchecked_mul(y);
2601+
}
2602+
}
2603+
};
2604+
}
2605+
2606+
// Use for NonZero what already worked well for general numeric types (see num/mod.rs)
2607+
macro_rules! check_mul_unchecked_intervals {
2608+
($t:ty, $nonzero_type:ty, $nonzero_check_mul_for:ident, $min:expr, $max:expr) => {
2609+
#[kani::proof_for_contract(NonZero::<$t>::unchecked_mul)]
2610+
pub fn $nonzero_check_mul_for() {
2611+
let x = kani::any::<$t>();
2612+
let y = kani::any::<$t>();
2613+
2614+
kani::assume(x != 0 && x >= $min && x <= $max);
2615+
kani::assume(y != 0 && y >= $min && y <= $max);
2616+
2617+
let x = <$nonzero_type>::new(x).unwrap();
2618+
let y = <$nonzero_type>::new(y).unwrap();
2619+
2620+
unsafe {
2621+
x.unchecked_mul(y);
2622+
}
2623+
}
2624+
};
2625+
}
2626+
2627+
//Calls for i32
2628+
check_mul_unchecked_intervals!(
2629+
i32,
2630+
NonZeroI32,
2631+
check_mul_i32_small,
2632+
NonZeroI32::new(-10i32).unwrap().into(),
2633+
NonZeroI32::new(10i32).unwrap().into()
2634+
);
2635+
check_mul_unchecked_intervals!(
2636+
i32,
2637+
NonZeroI32,
2638+
check_mul_i32_large_pos,
2639+
NonZeroI32::new(i32::MAX - 1000i32).unwrap().into(),
2640+
NonZeroI32::new(i32::MAX).unwrap().into()
2641+
);
2642+
check_mul_unchecked_intervals!(
2643+
i32,
2644+
NonZeroI32,
2645+
check_mul_i32_large_neg,
2646+
NonZeroI32::new(i32::MIN + 1000i32).unwrap().into(),
2647+
NonZeroI32::new(i32::MIN + 1).unwrap().into()
2648+
);
2649+
check_mul_unchecked_intervals!(
2650+
i32,
2651+
NonZeroI32,
2652+
check_mul_i32_edge_pos,
2653+
NonZeroI32::new(i32::MAX / 2).unwrap().into(),
2654+
NonZeroI32::new(i32::MAX).unwrap().into()
2655+
);
2656+
check_mul_unchecked_intervals!(
2657+
i32,
2658+
NonZeroI32,
2659+
check_mul_i32_edge_neg,
2660+
NonZeroI32::new(i32::MIN / 2).unwrap().into(),
2661+
NonZeroI32::new(i32::MIN + 1).unwrap().into()
2662+
);
2663+
2664+
//Calls for i64
2665+
check_mul_unchecked_intervals!(
2666+
i64,
2667+
NonZeroI64,
2668+
check_mul_i64_small,
2669+
NonZeroI64::new(-10i64).unwrap().into(),
2670+
NonZeroI64::new(10i64).unwrap().into()
2671+
);
2672+
check_mul_unchecked_intervals!(
2673+
i64,
2674+
NonZeroI64,
2675+
check_mul_i64_large_pos,
2676+
NonZeroI64::new(i64::MAX - 1000i64).unwrap().into(),
2677+
NonZeroI64::new(i64::MAX).unwrap().into()
2678+
);
2679+
check_mul_unchecked_intervals!(
2680+
i64,
2681+
NonZeroI64,
2682+
check_mul_i64_large_neg,
2683+
NonZeroI64::new(i64::MIN + 1000i64).unwrap().into(),
2684+
NonZeroI64::new(i64::MIN + 1).unwrap().into()
2685+
);
2686+
check_mul_unchecked_intervals!(
2687+
i64,
2688+
NonZeroI64,
2689+
check_mul_i64_edge_pos,
2690+
NonZeroI64::new(i64::MAX / 2).unwrap().into(),
2691+
NonZeroI64::new(i64::MAX).unwrap().into()
2692+
);
2693+
check_mul_unchecked_intervals!(
2694+
i64,
2695+
NonZeroI64,
2696+
check_mul_i64_edge_neg,
2697+
NonZeroI64::new(i64::MIN / 2).unwrap().into(),
2698+
NonZeroI64::new(i64::MIN + 1).unwrap().into()
2699+
);
2700+
2701+
//calls for i128
2702+
check_mul_unchecked_intervals!(
2703+
i128,
2704+
NonZeroI128,
2705+
check_mul_i128_small,
2706+
NonZeroI128::new(-10i128).unwrap().into(),
2707+
NonZeroI128::new(10i128).unwrap().into()
2708+
);
2709+
check_mul_unchecked_intervals!(
2710+
i128,
2711+
NonZeroI128,
2712+
check_mul_i128_large_pos,
2713+
NonZeroI128::new(i128::MAX - 1000i128).unwrap().into(),
2714+
NonZeroI128::new(i128::MAX).unwrap().into()
2715+
);
2716+
check_mul_unchecked_intervals!(
2717+
i128,
2718+
NonZeroI128,
2719+
check_mul_i128_large_neg,
2720+
NonZeroI128::new(i128::MIN + 1000i128).unwrap().into(),
2721+
NonZeroI128::new(i128::MIN + 1).unwrap().into()
2722+
);
2723+
check_mul_unchecked_intervals!(
2724+
i128,
2725+
NonZeroI128,
2726+
check_mul_i128_edge_pos,
2727+
NonZeroI128::new(i128::MAX / 2).unwrap().into(),
2728+
NonZeroI128::new(i128::MAX).unwrap().into()
2729+
);
2730+
check_mul_unchecked_intervals!(
2731+
i128,
2732+
NonZeroI128,
2733+
check_mul_i128_edge_neg,
2734+
NonZeroI128::new(i128::MIN / 2).unwrap().into(),
2735+
NonZeroI128::new(i128::MIN + 1).unwrap().into()
2736+
);
2737+
2738+
//calls for isize
2739+
check_mul_unchecked_intervals!(
2740+
isize,
2741+
NonZeroIsize,
2742+
check_mul_isize_small,
2743+
NonZeroIsize::new(-10isize).unwrap().into(),
2744+
NonZeroIsize::new(10isize).unwrap().into()
2745+
);
2746+
check_mul_unchecked_intervals!(
2747+
isize,
2748+
NonZeroIsize,
2749+
check_mul_isize_large_pos,
2750+
NonZeroIsize::new(isize::MAX - 1000isize).unwrap().into(),
2751+
NonZeroIsize::new(isize::MAX).unwrap().into()
2752+
);
2753+
check_mul_unchecked_intervals!(
2754+
isize,
2755+
NonZeroIsize,
2756+
check_mul_isize_large_neg,
2757+
NonZeroIsize::new(isize::MIN + 1000isize).unwrap().into(),
2758+
NonZeroIsize::new(isize::MIN + 1).unwrap().into()
2759+
);
2760+
check_mul_unchecked_intervals!(
2761+
isize,
2762+
NonZeroIsize,
2763+
check_mul_isize_edge_pos,
2764+
NonZeroIsize::new(isize::MAX / 2).unwrap().into(),
2765+
NonZeroIsize::new(isize::MAX).unwrap().into()
2766+
);
2767+
check_mul_unchecked_intervals!(
2768+
isize,
2769+
NonZeroIsize,
2770+
check_mul_isize_edge_neg,
2771+
NonZeroIsize::new(isize::MIN / 2).unwrap().into(),
2772+
NonZeroIsize::new(isize::MIN + 1).unwrap().into()
2773+
);
2774+
2775+
//calls for u32
2776+
check_mul_unchecked_intervals!(
2777+
u32,
2778+
NonZeroU32,
2779+
check_mul_u32_small,
2780+
NonZeroU32::new(1u32).unwrap().into(),
2781+
NonZeroU32::new(10u32).unwrap().into()
2782+
);
2783+
check_mul_unchecked_intervals!(
2784+
u32,
2785+
NonZeroU32,
2786+
check_mul_u32_large,
2787+
NonZeroU32::new(u32::MAX - 1000u32).unwrap().into(),
2788+
NonZeroU32::new(u32::MAX).unwrap().into()
2789+
);
2790+
check_mul_unchecked_intervals!(
2791+
u32,
2792+
NonZeroU32,
2793+
check_mul_u32_edge,
2794+
NonZeroU32::new(u32::MAX / 2).unwrap().into(),
2795+
NonZeroU32::new(u32::MAX).unwrap().into()
2796+
);
2797+
2798+
//calls for u64
2799+
check_mul_unchecked_intervals!(
2800+
u64,
2801+
NonZeroU64,
2802+
check_mul_u64_small,
2803+
NonZeroU64::new(1u64).unwrap().into(),
2804+
NonZeroU64::new(10u64).unwrap().into()
2805+
);
2806+
check_mul_unchecked_intervals!(
2807+
u64,
2808+
NonZeroU64,
2809+
check_mul_u64_large,
2810+
NonZeroU64::new(u64::MAX - 1000u64).unwrap().into(),
2811+
NonZeroU64::new(u64::MAX).unwrap().into()
2812+
);
2813+
check_mul_unchecked_intervals!(
2814+
u64,
2815+
NonZeroU64,
2816+
check_mul_u64_edge,
2817+
NonZeroU64::new(u64::MAX / 2).unwrap().into(),
2818+
NonZeroU64::new(u64::MAX).unwrap().into()
2819+
);
2820+
2821+
//calls for u128
2822+
check_mul_unchecked_intervals!(
2823+
u128,
2824+
NonZeroU128,
2825+
check_mul_u128_small,
2826+
NonZeroU128::new(1u128).unwrap().into(),
2827+
NonZeroU128::new(10u128).unwrap().into()
2828+
);
2829+
check_mul_unchecked_intervals!(
2830+
u128,
2831+
NonZeroU128,
2832+
check_mul_u128_large,
2833+
NonZeroU128::new(u128::MAX - 1000u128).unwrap().into(),
2834+
NonZeroU128::new(u128::MAX).unwrap().into()
2835+
);
2836+
check_mul_unchecked_intervals!(
2837+
u128,
2838+
NonZeroU128,
2839+
check_mul_u128_edge,
2840+
NonZeroU128::new(u128::MAX / 2).unwrap().into(),
2841+
NonZeroU128::new(u128::MAX).unwrap().into()
2842+
);
2843+
2844+
//calls for usize
2845+
check_mul_unchecked_intervals!(
2846+
usize,
2847+
NonZeroUsize,
2848+
check_mul_usize_small,
2849+
NonZeroUsize::new(1usize).unwrap().into(),
2850+
NonZeroUsize::new(10usize).unwrap().into()
2851+
);
2852+
check_mul_unchecked_intervals!(
2853+
usize,
2854+
NonZeroUsize,
2855+
check_mul_usize_large,
2856+
NonZeroUsize::new(usize::MAX - 1000usize).unwrap().into(),
2857+
NonZeroUsize::new(usize::MAX).unwrap().into()
2858+
);
2859+
check_mul_unchecked_intervals!(
2860+
usize,
2861+
NonZeroUsize,
2862+
check_mul_usize_edge,
2863+
NonZeroUsize::new(usize::MAX / 2).unwrap().into(),
2864+
NonZeroUsize::new(usize::MAX).unwrap().into()
2865+
);
2866+
2867+
//calls for i8, i16, u8, u16
2868+
check_mul_unchecked_small!(i8, NonZeroI8, nonzero_check_mul_for_i8);
2869+
check_mul_unchecked_small!(i16, NonZeroI16, nonzero_check_mul_for_i16);
2870+
check_mul_unchecked_small!(u8, NonZeroU8, nonzero_check_mul_for_u8);
2871+
check_mul_unchecked_small!(u16, NonZeroU16, nonzero_check_mul_for_u16);
2872+
2873+
macro_rules! nonzero_check_add {
2874+
($t:ty, $nonzero_type:ty, $nonzero_check_unchecked_add_for:ident) => {
2875+
#[kani::proof_for_contract(NonZero::<$t>::unchecked_add)]
2876+
pub fn $nonzero_check_unchecked_add_for() {
2877+
let x: $nonzero_type = kani::any();
2878+
let y: $t = kani::any();
2879+
2880+
unsafe {
2881+
x.unchecked_add(y);
2882+
}
2883+
}
2884+
};
2885+
}
2886+
2887+
nonzero_check_add!(u8, core::num::NonZeroU8, nonzero_check_unchecked_add_for_u8);
2888+
nonzero_check_add!(u16, core::num::NonZeroU16, nonzero_check_unchecked_add_for_u16);
2889+
nonzero_check_add!(u32, core::num::NonZeroU32, nonzero_check_unchecked_add_for_u32);
2890+
nonzero_check_add!(u64, core::num::NonZeroU64, nonzero_check_unchecked_add_for_u64);
2891+
nonzero_check_add!(u128, core::num::NonZeroU128, nonzero_check_unchecked_add_for_u128);
2892+
nonzero_check_add!(usize, core::num::NonZeroUsize, nonzero_check_unchecked_add_for_usize);
25782893
}

0 commit comments

Comments
 (0)