Skip to content

Commit 3736d54

Browse files
Fix Layout::repeat contract and f128->i128 harness failures
Two harness failures surfaced in CI once compilation was fixed: * alloc::layout::verify::check_repeat: rust-lang#148769 changed Layout::repeat to not include padding after the trailing element, so on success the resulting size is (n - 1) * stride + self.size() rather than n * stride. Our postcondition size >= stride is thus violated for n == 1 whenever self needs padding (e.g. size 6, align 4: size 6 < stride 8). Update the exact (non-kani) postconditions to the new semantics and weaken the Kani-checkable variant to n <= 1 || size >= stride. * num::verify::checked_f128_to_int_unchecked_i128: Kani's f128 -> i128 lower bound in float_to_int_in_range is unsound (-2^128 instead of -(2^127 + 2^15)), so the contract instrumentation admits values that truncate below i128::MIN; the CBMC 6.10 upgrade in the new Kani pin exposed this (previously such conversions happened to saturate the same way as the 'as' oracle). Reported as model-checking/kani#4662, fix proposed in model-checking/kani#4663. Until that fix is in the pinned Kani version, hand-write this harness with an explicit sound input range. Verified locally with the pinned Kani commit: both harnesses pass, and 'cargo check -p core' stays clean. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
1 parent a855779 commit 3736d54

2 files changed

Lines changed: 31 additions & 10 deletions

File tree

library/core/src/alloc/layout.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,19 +461,21 @@ impl Layout {
461461
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
462462
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
463463
#[inline]
464-
// for Kani (v0.54.0), the below modulo operation is too costly to prove (running into the
465-
// 6-hours timeout on GitHub); we use a weaker postcondition instead
464+
// Since rust-lang/rust#148769, the result does not include padding after the trailing
465+
// element, i.e., on success the resulting size is (n - 1) * stride + self.size() for n > 0
466+
// (and 0 for n == 0), where stride is the returned offset.
467+
// for Kani (v0.54.0), multiplication by a symbolic n is too costly to prove (running into
468+
// the 6-hours timeout on GitHub); we use weaker postconditions instead
466469
#[cfg_attr(not(kani),
467-
ensures(|result| result.is_err() || n == 0 || result.as_ref().unwrap().0.size() % n == 0))]
470+
ensures(|result| result.is_err() || n == 0 ||
471+
result.as_ref().unwrap().0.size() ==
472+
(n - 1) * result.as_ref().unwrap().1 + self.size()))]
468473
#[cfg_attr(kani,
469474
ensures(|result| result.is_err() || n == 0 || result.as_ref().unwrap().0.size() >= self.size()))]
470-
// for Kani (v0.54.0), the below multiplication is too costly to prove (running into the
471-
// 6-hours timeout on GitHub); we use a weaker postcondition instead
472475
#[cfg_attr(not(kani),
473-
ensures(|result| result.is_err() ||
474-
result.as_ref().unwrap().0.size() == n * result.as_ref().unwrap().1))]
476+
ensures(|result| result.is_err() || n != 0 || result.as_ref().unwrap().0.size() == 0))]
475477
#[cfg_attr(kani,
476-
ensures(|result| result.is_err() || n == 0 ||
478+
ensures(|result| result.is_err() || n <= 1 ||
477479
result.as_ref().unwrap().0.size() >= result.as_ref().unwrap().1))]
478480
pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
479481
// FIXME(const-hack): the following could be way shorter with `?`

library/core/src/num/mod.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,8 +2175,6 @@ mod verify {
21752175
checked_f128_to_int_unchecked_i32,
21762176
i64,
21772177
checked_f128_to_int_unchecked_i64,
2178-
i128,
2179-
checked_f128_to_int_unchecked_i128,
21802178
isize,
21812179
checked_f128_to_int_unchecked_isize,
21822180
u8,
@@ -2192,4 +2190,25 @@ mod verify {
21922190
usize,
21932191
checked_f128_to_int_unchecked_usize
21942192
);
2193+
2194+
// FIXME(kani): this harness is hand-written (instead of being generated via
2195+
// generate_to_int_unchecked_harness! above) because Kani's f128 -> i128 lower bound in
2196+
// float_to_int_in_range is unsound (-2^128 instead of -(2^127 + 2^15)), so the contract
2197+
// instrumentation admits out-of-range values; see
2198+
// https://github.com/model-checking/kani/issues/4662. Until the fix
2199+
// (https://github.com/model-checking/kani/pull/4663) is part of the Kani version pinned
2200+
// here, constrain the input to the sound range explicitly.
2201+
#[kani::proof_for_contract(f128::to_int_unchecked)]
2202+
pub fn checked_f128_to_int_unchecked_i128() {
2203+
let num1: f128 = kani::any_where(|f: &f128| {
2204+
// -(2^127 + 2^15) is the largest f128 whose truncation is below i128::MIN;
2205+
// require the value to be strictly above it (and below i128::MAX + 1 = 2^127).
2206+
f.is_finite()
2207+
&& *f > -170141183460469231731687303715884138496.0
2208+
&& *f < 170141183460469231731687303715884105728.0
2209+
});
2210+
let result = unsafe { num1.to_int_unchecked::<i128>() };
2211+
2212+
assert_eq!(result, num1 as i128);
2213+
}
21952214
}

0 commit comments

Comments
 (0)