Skip to main content

BoundedReader

Trait BoundedReader 

Source
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 an Err if 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 growable Vec. 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§

Source

fn remaining(&self) -> usize

Bytes still unread in the current message buffer. The ceiling on any count-driven allocation.

Provided Methods§

Source

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.

Source

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".

Implementors§