Skip to content

Commit b23d05f

Browse files
committed
Use bounded exponent for NonZeroI128/U128 saturating_pow harnesses
The 128-bit saturating_pow harnesses with unbounded u32 exponents hit CBMC's 10-minute timeout because 128-bit bitvector multiplication is extremely expensive. Add a dedicated macro that constrains exp <= 10 with unwind(5), sufficient to cover both the non-saturating and saturating code paths while keeping verification tractable.
1 parent 8267fcb commit b23d05f

File tree

1 file changed

+21
-2
lines changed

1 file changed

+21
-2
lines changed

library/core/src/num/nonzero.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,15 +3541,34 @@ mod verify {
35413541
nonzero_check_saturating_pow!(core::num::NonZeroI16, nonzero_check_saturating_pow_i16);
35423542
nonzero_check_saturating_pow!(core::num::NonZeroI32, nonzero_check_saturating_pow_i32);
35433543
nonzero_check_saturating_pow!(core::num::NonZeroI64, nonzero_check_saturating_pow_i64);
3544-
nonzero_check_saturating_pow!(core::num::NonZeroI128, nonzero_check_saturating_pow_i128);
35453544
nonzero_check_saturating_pow!(core::num::NonZeroIsize, nonzero_check_saturating_pow_isize);
35463545
nonzero_check_saturating_pow!(core::num::NonZeroU8, nonzero_check_saturating_pow_u8);
35473546
nonzero_check_saturating_pow!(core::num::NonZeroU16, nonzero_check_saturating_pow_u16);
35483547
nonzero_check_saturating_pow!(core::num::NonZeroU32, nonzero_check_saturating_pow_u32);
35493548
nonzero_check_saturating_pow!(core::num::NonZeroU64, nonzero_check_saturating_pow_u64);
3550-
nonzero_check_saturating_pow!(core::num::NonZeroU128, nonzero_check_saturating_pow_u128);
35513549
nonzero_check_saturating_pow!(core::num::NonZeroUsize, nonzero_check_saturating_pow_usize);
35523550

3551+
// 128-bit types use a bounded exponent to avoid CBMC timeout: saturating_pow
3552+
// uses binary exponentiation (O(log2(exp)) 128-bit multiplications), which is
3553+
// extremely expensive for CBMC's bitvector encoding. Bounding exp <= 10 is
3554+
// sufficient to exercise both the non-saturating and saturating code paths
3555+
// while keeping verification tractable (ceil(log2(10)) ≈ 4 loop iterations).
3556+
macro_rules! nonzero_check_saturating_pow_128 {
3557+
($nonzero_type:ty, $harness:ident) => {
3558+
#[kani::proof]
3559+
#[kani::unwind(5)]
3560+
pub fn $harness() {
3561+
let x: $nonzero_type = kani::any();
3562+
let exp: u32 = kani::any_where(|&e| e <= 10);
3563+
let result = x.saturating_pow(exp);
3564+
assert!(result.get() != 0);
3565+
}
3566+
};
3567+
}
3568+
3569+
nonzero_check_saturating_pow_128!(core::num::NonZeroI128, nonzero_check_saturating_pow_i128);
3570+
nonzero_check_saturating_pow_128!(core::num::NonZeroU128, nonzero_check_saturating_pow_u128);
3571+
35533572
// --- Unsigned-only operations ---
35543573

35553574
macro_rules! nonzero_check_checked_next_power_of_two {

0 commit comments

Comments
 (0)