From 1d0c347f047984a241ffe117daa04d6965ee460d Mon Sep 17 00:00:00 2001 From: Geoffrey Oxberry Date: Fri, 22 May 2026 18:47:09 +0000 Subject: [PATCH] refactor(payload): mark in-function invariants as unreachable!() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six `usize → u32` and `Option` `.expect()` sites in `lading_payload` are guarded by invariants established earlier in the same function (or at pool construction): - `block.rs:752` — `bytes.len().try_into()` to u32 inside `construct_block`; `bytes` is sized by `chunk_size: u32`. - `random_string_pool.rs:125,127` — `lower_idx.try_into()` and `bytes.try_into()` for `Handle::PosAndLength(u32, u32)`. The pool's inner length is asserted to fit in u32 at construction (`with_size` line 35); `lower_idx` and `bytes` are both bounded by it. - `string_list_pool.rs:253,260` — `u32::try_from(idx)` inside `range_value_at`; `idx` is bounded by the range length, which fits in u32 by construction. - `string_list_pool.rs:256` — `char::from_u32(*start as u32 + offset)` inside the same function; `*start..=*end` is a valid Unicode scalar range by parser invariant. Same pattern as #1884 and #1885. No runtime behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 10 ++++++++++ lading_payload/src/block.rs | 9 +++------ .../src/common/strings/random_string_pool.rs | 6 ++++-- .../src/common/strings/string_list_pool.rs | 14 +++++++++++--- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02258af49..243213ea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +- Replaced 6 in-function-invariant `.expect()` sites in `lading_payload` + with `.unwrap_or_else(|_| unreachable!("..."))` / + `.unwrap_or_else(|| unreachable!("..."))`. Covered: `usize → u32` + conversions in `block::construct_block`, + `random_string_pool::of_size_with_handle` (×2), and + `string_list_pool::range_value_at` (×2, plus one + `char::from_u32(...)` on values produced by char range expansion). + All sites are guarded by invariants established earlier in the same + function or at pool construction (`with_size` asserts pool length + fits in u32). No runtime behavior change. - Replaced 5 additional infallible-by-construction `.expect()` sites in `lading_payload` with `.unwrap_or_else(|_| unreachable!("..."))` / `.unwrap_or_else(|| unreachable!("..."))`. Covered: 4 sites in diff --git a/lading_payload/src/block.rs b/lading_payload/src/block.rs index bbf6be576..62e2b0327 100644 --- a/lading_payload/src/block.rs +++ b/lading_payload/src/block.rs @@ -745,12 +745,9 @@ where // serializer. Err(SpinError::EmptyBlock) } else { - let total_bytes = NonZeroU32::new( - bytes - .len() - .try_into() - .expect("failed to get length of bytes"), - ) + let total_bytes = NonZeroU32::new(bytes.len().try_into().unwrap_or_else(|_| { + unreachable!("bytes.len() fits in u32: blocks are sized by chunk_size: u32") + })) .ok_or(SpinError::Zero)?; let mut metadata = BlockMetadata::default(); diff --git a/lading_payload/src/common/strings/random_string_pool.rs b/lading_payload/src/common/strings/random_string_pool.rs index b168b5213..b07bb7f2a 100644 --- a/lading_payload/src/common/strings/random_string_pool.rs +++ b/lading_payload/src/common/strings/random_string_pool.rs @@ -122,8 +122,10 @@ impl Pool for RandomStringPool { Handle::PosAndLength( lower_idx .try_into() - .expect("must fit into u32 by construction"), - bytes.try_into().expect("must fit in u32 by construction"), + .unwrap_or_else(|_| unreachable!("lower_idx < self.inner.len(), and self.inner.len() fits in u32 by the assert in with_size")), + bytes + .try_into() + .unwrap_or_else(|_| unreachable!("bytes < self.inner.len(), and self.inner.len() fits in u32 by the assert in with_size")), ), )) } diff --git a/lading_payload/src/common/strings/string_list_pool.rs b/lading_payload/src/common/strings/string_list_pool.rs index 798a60484..967eb2135 100644 --- a/lading_payload/src/common/strings/string_list_pool.rs +++ b/lading_payload/src/common/strings/string_list_pool.rs @@ -250,13 +250,21 @@ fn range_len(range: &PatternRange) -> Result { fn range_value_at(range: &PatternRange, idx: usize) -> String { match range { PatternRange::Char(start, _end) => char::from_u32( - *start as u32 + u32::try_from(idx).expect("pattern shouldn't be that big"), + *start as u32 + + u32::try_from(idx).unwrap_or_else(|_| { + unreachable!("idx is bounded by range length, which fits in u32") + }), ) - .expect("idx is within range bounds") + .unwrap_or_else(|| { + unreachable!("char range expansion produces valid Unicode scalars by construction") + }) .to_string(), PatternRange::Number(start, end) => { let numdigits = std::cmp::max(start.to_string().len(), end.to_string().len()); - let n = start + u32::try_from(idx).expect("pattern shouldn't be that big"); + let n = start + + u32::try_from(idx).unwrap_or_else(|_| { + unreachable!("idx is bounded by range length, which fits in u32") + }); format!("{n:0numdigits$}") } }