1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! Kani proof harnesses (hardening gate H-30).
//!
//! Compiled only under `cfg(kani)`, so this module costs the shipped crate
//! nothing. Run with `cargo kani -p rusty_alloc`.
//!
//! **What a proof is for here.** The rest of the gate ladder is empirical:
//! Miri interprets the paths a test happens to take, the fuzzers sample
//! ~7M inputs, loom exhausts a small interleaving space. All three answer
//! "no counterexample was FOUND". Kani answers "no counterexample EXISTS"
//! over a symbolic input range — which is the right instrument for the
//! arithmetic that every `unsafe` block in this crate rests on:
//!
//! * `page_of`'s slice index is `< SLICES_PER_SEGMENT` for EVERY pointer
//! inside a segment. That bound is the contract discharged at all eight
//! call sites and the reason the bounds check was removed (M10b brick
//! #4). If it can fail for any offset, that removal is a memory-safety
//! bug rather than an optimisation.
//! * `slice_offset` fits the `u16` it is stored in — currently guarded by
//! a const assert; proved here over the whole index range.
//! * the bin geometry never returns an out-of-range queue index and
//! `good_size` never shrinks a request, for every size — the two
//! properties the direct table and every queue index depend on.
use cratebins;
use crate;
/// `page_of` computes `idx = (p - seg) / SEGMENT_SLICE_SIZE` and then indexes
/// `[Page; SLICES_PER_SEGMENT]` WITHOUT a bounds check, on the argument that
/// `p` lies inside the segment by the caller's contract. Prove that argument
/// holds for every in-segment offset, not merely the ones a test tried.
/// The `slice_offset` field is a `u16` holding a SLICE distance back to the
/// span start (M12; bytes until 2026-08-22). Prove the encoding cannot
/// overflow for any interior slot — the const assert checks only the maximum,
/// this checks every index. Also prove the byte distance the `debug_assert` in
/// `page_of` reconstructs from it stays in range, since that scaling is where
/// the old overflow risk lived.
/// Every size maps to a queue index the heap actually has. A bin outside
/// `0..=BIN_FULL` would index `Heap::pages` out of range on the allocation
/// path.
/// **Bounded**, and the bound is part of the claim: CBMC reasons
/// bit-precisely, and `bin`/`good_size` use `leading_zeros` and variable
/// shifts, so an unbounded 64-bit domain does not terminate in usable time
/// (measured: >13 CPU-minutes, killed). The domain below covers every
/// structural case the function has — small bins, the MI_ALIGN2W region, the
/// four-per-power-of-two region, and BOTH sides of the MEDIUM_OBJ_SIZE_MAX
/// cutoff — which is what the proof is about. Sizes beyond it differ only in
/// magnitude, and the property test covers those empirically.
/// `good_size` is the ABI-visible promise a caller sizes buffers against: it
/// must never return less than requested. Proved for every size rather than
/// the 2 million the property test samples.
/// Bounded for the same reason as the proof above; the domain spans both
/// sides of the binned cutoff, which is where the rounding changes shape.
/// The small-malloc fast path indexes `direct[wsize_from_size(size)]`, an
/// array of `PAGES_DIRECT` entries, with NO bounds check on the hot path.
/// Prove the index is in range for every size the fast path accepts.