pub trait BoundedReader {
// Required method
fn remaining(&self) -> usize;
// Provided methods
fn alloc_count_checked(
&self,
count: usize,
min_bytes_per_elem: usize,
) -> Result<usize> { ... }
fn with_capacity_bounded<T>(
&self,
count: usize,
min_bytes_per_elem: usize,
) -> Vec<T> { ... }
}Expand description
The structural OOM-from-length invariant for every wire decoder.
A length/count field read from the wire can never drive an allocation
larger than the bytes actually remaining in the current message buffer: you
cannot have N elements if fewer than N * min_bytes_per_elem bytes remain.
Every reader over an untrusted buffer (TtcReader, the OSON / DbObject /
notification cursors, the VECTOR reader) implements this trait, and every
count-driven Vec::with_capacity / reserve in the decoders routes through
one of its two methods instead of trusting a raw u16/u32/u64 count.
This closes the OOM-from-length bug class by construction: a new decoder
physically cannot pre-allocate from a wire count without going through a
bound, because the raw Vec::with_capacity(count) shape is the thing we
audit against (see docs/FUZZING.md).
Two flavors, both anchored on remaining:
alloc_count_checked— fail closed early: returns anErrif the declared count cannot possibly fit, before any allocation. Use where an oversized count is unambiguously malformed.with_capacity_bounded— cap the pre-allocation at what the buffer could hold while still returning a normal growableVec. Use where the loop body itself fails closed on the first truncated element read; legitimate large payloads keep working because the cap equals the honest count whenever the bytes are really there.
Required Methods§
Provided Methods§
Sourcefn alloc_count_checked(
&self,
count: usize,
min_bytes_per_elem: usize,
) -> Result<usize>
fn alloc_count_checked( &self, count: usize, min_bytes_per_elem: usize, ) -> Result<usize>
Validate a server-declared element count against the buffer: a run of
count elements must carry at least count * min_bytes_per_elem bytes,
so a count whose minimum byte footprint exceeds [remaining] is a lie.
Returns the (unchanged) count when it fits, or a fail-closed
ProtocolError::TtcDecode otherwise — never a panic, never an OOM.
min_bytes_per_elem is the minimum on-wire size of one element (e.g.
4 for a u32 index, 8 for an f64, 1 for a length-prefixed field whose
shortest legal form is a single length byte). A zero is treated as 1.
Sourcefn with_capacity_bounded<T>(
&self,
count: usize,
min_bytes_per_elem: usize,
) -> Vec<T>
fn with_capacity_bounded<T>( &self, count: usize, min_bytes_per_elem: usize, ) -> Vec<T>
Pre-size a Vec for count elements without trusting count: the
reserved capacity is capped at remaining() / min_bytes_per_elem, the
largest number of elements the buffer could actually hold. The returned
Vec is a normal growable Vec, so a legitimately large payload (where
count really fits) is pre-sized to the honest count, and a streamed /
chunked field that grows past the initial buffer still appends correctly
— the cap only governs the speculative up-front reservation.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".