Commit a801db5
Fix OffsetModel missing UB for offsets wrapping CBMC's pointer encoding
CBMC encodes pointers as an (object, offset) pair where the offset
field has pointer_width - object_bits bits. Pointer arithmetic
therefore wraps offsets at 2^(64 - object_bits) rather than 2^64
(#1150). For the
OffsetModel this meant that a symbolic byte offset that is a non-zero
multiple of 2^(64 - object_bits) (2^48 with Kani's default of 16
object bits) made `wrapping_byte_offset` alias the original pointer,
so the subsequent same-allocation safety check passed spuriously and
genuine out-of-bounds `offset` calls verified successfully - including
"proving" the false fact that the result equals the base pointer.
Detect the wrap by additionally requiring that the address of the
result is consistent with full-width integer arithmetic on the address
of the original pointer; any truncation in the pointer addition
falsifies this equation. Two alternative formulations do not work:
* Computing the new pointer via integer arithmetic
(addr().wrapping_add_signed(off) followed by a cast back, as
previously suggested in a FIXME here) is sound, but makes the solver
case-split the integer address over every object; harnesses using
e.g. `sort()` then run out of memory. These are the "unexpected
failures" mentioned in the removed comment (reproduced on:
expected/cover/cover-pass, expected/string-repeat,
expected/loop-backedge, expected/shadow/unsupported_num_objects).
* Comparing POINTER_OFFSET(new) against full-width
POINTER_OFFSET(orig) + offset is defeated by CBMC's simplifier,
which rewrites POINTER_OFFSET(p + k) to POINTER_OFFSET(p) + k in
full-width arithmetic, making the equation trivially true.
The `addr()` transmute is opaque to that simplification, keeps all
operations in the pointer domain, and adds negligible solver cost:
the full expected (459) and kani (593) suites pass unchanged.
The underlying encoding wrap is fixed on the CBMC side in
diffblue/cbmc#9134 (out-of-range results are
directed to the invalid object). The equation here also states Rust's
address-arithmetic contract for `offset` and produces the same verdicts
with and without that CBMC fix, so it is kept as a semantic guard
rather than a version-specific workaround.
Partially addresses #1150: this fixes the missed-UB soundness hole in
the checked `offset`/`arith_offset` intrinsic model. Not addressed is
the `wrapping_offset` family, which Kani codegens to plain CBMC pointer
addition: under CBMC versions without the encoding fix its result
aliases the base pointer for wrap-multiple offsets
(tests/kani/PointerOffset/fixme_wrap_nonzero_offset.rs), and even with
the CBMC fix the result address is indeterminate rather than the
exactly-wrapped address that Rust defines. Exact modeling would require
integer arithmetic plus an integer-to-pointer cast, which makes the
solver case-split over all objects (see above).
Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>1 parent 1c9134a commit a801db5
3 files changed
Lines changed: 100 additions & 7 deletions
File tree
- library/kani_core/src
- tests/expected/offset-bounds-check
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
128 | | - | |
129 | | - | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
130 | 131 | | |
131 | | - | |
132 | | - | |
133 | | - | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
134 | 156 | | |
| 157 | + | |
135 | 158 | | |
136 | | - | |
| 159 | + | |
137 | 160 | | |
138 | 161 | | |
139 | 162 | | |
| |||
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 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 | + | |
0 commit comments