Skip to content

Commit 4e537c7

Browse files
committed
contract: checked_add overflow guard in verify_layout + MD040 fix
Two CodeRabbit fixes for PR #477: 1. soa_envelope.rs — checked_add overflow guard (Major finding) verify_layout() now computes every column's byte-range end via checked_add rather than raw usize addition. On 32-bit targets (wasm32), row_offset (u32 ≤ 4.29e9) + col_bytes can exceed usize::MAX and wrap to a small value that would silently pass the `a_end > stride` check. The new closure returns ColumnOutOfBounds on overflow, covering both positional overflow and wasm32-wrap in one code path. 2. soa-three-tier-model.md — add `text` language tag (MD040) The layout table code fence was untagged. Added `text` to satisfy the no-language-specified lint. The CodeRabbit "critical" finding about MailboxSoaSnapshot violating zero-dep is NOT fixed here — that finding is architecturally incorrect. ndarray IS a declared dependency per workspace policy; the plan is correct as-is. https://claude.ai/code/session_0147hSzjmWZDuy2MSQNrhEK5
1 parent 2af4654 commit 4e537c7

2 files changed

Lines changed: 19 additions & 3 deletions

File tree

crates/lance-graph-contract/src/soa_envelope.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,23 @@ pub trait SoaEnvelope {
194194
let cols = self.columns();
195195
let mut summed = 0usize;
196196
let stride = self.row_stride();
197+
// `row_offset as usize + col_bytes` can wrap on 32-bit targets (wasm32):
198+
// row_offset is u32 (≤ 4.29e9) and col_bytes can reach 8 × 65535, so the
199+
// sum can exceed usize::MAX on a 32-bit usize and wrap to a small value
200+
// that would slip past the `a_end > stride` check. Compute every end with
201+
// checked_add and reject overflow as ColumnOutOfBounds.
202+
let checked_end = |c: &ColumnDescriptor| -> Result<usize, EnvelopeError> {
203+
(c.row_offset as usize)
204+
.checked_add(c.col_bytes_per_row())
205+
.ok_or(EnvelopeError::ColumnOutOfBounds {
206+
col: c.name_id,
207+
col_end: usize::MAX,
208+
stride,
209+
})
210+
};
197211
for (i, a) in cols.iter().enumerate() {
198-
let (a_start, a_end) = a.row_byte_range();
212+
let a_start = a.row_offset as usize;
213+
let a_end = checked_end(a)?;
199214
summed += a.col_bytes_per_row();
200215
if a_end > stride {
201216
return Err(EnvelopeError::ColumnOutOfBounds {
@@ -205,7 +220,8 @@ pub trait SoaEnvelope {
205220
});
206221
}
207222
for b in &cols[i + 1..] {
208-
let (b_start, b_end) = b.row_byte_range();
223+
let b_start = b.row_offset as usize;
224+
let b_end = checked_end(b)?;
209225
let overlap = a_start < b_end && b_start < a_end;
210226
if overlap {
211227
return Err(EnvelopeError::ColumnOverlap {

docs/architecture/soa-three-tier-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ The row is a register bank.
187187

188188
**Current / transitional layout** (target state removes `entity_type[N]` — see §3.2):
189189

190-
```
190+
```text
191191
Byte offset Width Column LE kind
192192
────────── ───── ────── ───────
193193
0 4·N energy[N] f32 × N

0 commit comments

Comments
 (0)