Skip to content

Commit 497cba4

Browse files
committed
Challenge 24: verify __iterator_get_unchecked via proof_for_contract
1 parent 815b42b commit 497cba4

1 file changed

Lines changed: 18 additions & 16 deletions

File tree

‎library/alloc/src/vec/into_iter.rs‎

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,25 +1147,27 @@ mod verify {
11471147
assert!(it.as_mut_slice().len() == n);
11481148
}
11491149

1150-
// __iterator_get_unchecked: the #[requires(i < self.len())] + kani::modifies
1151-
// contract already exists on this method. Kani cannot resolve a generic
1152-
// trait-impl method as a proof_for_contract target (kani#1997), so this
1153-
// harness is the mirroring assume-guarded proof: the assume mirrors the
1154-
// #[requires]; the assert checks the read's value against the source slice.
1155-
#[kani::proof]
1156-
#[kani::unwind(8)]
1150+
// __iterator_get_unchecked carries #[requires(i < self.len())] + kani::modifies(self).
1151+
// Resolved here at the u8/Global monomorphization as a proof_for_contract target, so this
1152+
// is a real contract proof: the #[requires] is enforced by Kani (no manual assume). The
1153+
// receiver is an arbitrary reachable state (symbolic front/back consumed), so the
1154+
// contract is verified over interior ptr positions, not only a fresh iterator. Spelled
1155+
// with the explicit Global allocator (the defaulted trailing type param).
1156+
#[kani::proof_for_contract(<IntoIter<u8, Global> as core::iter::Iterator>::__iterator_get_unchecked)]
1157+
#[kani::unwind(72)]
11571158
fn check_into_iter_get_unchecked_u8() {
1158-
let arr: [u8; 64] = kani::any();
1159-
let s = kani::slice::any_slice_of_array(&arr);
1160-
let mut it = s.to_vec().into_iter();
1161-
let len = it.len();
1162-
kani::assume(len > 0);
1159+
let (mut it, snapshot, front, _back) = any_reachable_u8_intoiter_snap::<64>();
11631160
let i: usize = kani::any();
1164-
kani::assume(i < len);
1165-
kani::cover(i == len - 1, "non-vacuity: the maximal valid index is reachable");
1166-
// SAFETY: i < len mirrors the documented #[requires] precondition.
1161+
// Non-vacuity: certify a non-empty reachable state with a maximal valid index is
1162+
// exercised (a bare contract SUCCESS cannot distinguish reachable from vacuous).
1163+
kani::cover(
1164+
it.len() > 0 && i == it.len() - 1,
1165+
"non-vacuity: maximal valid index reachable",
1166+
);
1167+
// #[requires(i < self.len())] is enforced by proof_for_contract — no manual assume.
11671168
let x = unsafe { it.__iterator_get_unchecked(i) };
1168-
assert!(x == s[i]);
1169+
// Reads offset i from the current front; element i is snapshot[front + i].
1170+
assert!(x == snapshot[front + i]);
11691171
}
11701172

11711173
// Drop: destroys the remaining elements (drop_in_place) + RawVec dealloc.

0 commit comments

Comments
 (0)