cultcache-rs docs: debug floor stated for a plain caller; first-frame sentences removed; Windows line names its run

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-14 21:19:13 +02:00
commit 10a39dac98
2 changed files with 14 additions and 11 deletions

View file

@ -459,7 +459,7 @@ manual registration ceremony, not to loosen the closed-world boundary.
Payload nesting is bounded at 256 MessagePack containers, checked before any
recursion; past the bound the refusal is a typed `PayloadTooDeep`. Typed decode
of stored bytes then grows its stack: the decoder checks the remaining stack
before its first frame and `serde_stacker` checks it at every container, moving
at entry and `serde_stacker` checks it at every container, moving
onto a fresh segment whenever less than 512 KiB remains, so a payload inside the
bound decodes on a small thread instead of aborting the process. Envelope and
store reads (single-file, redb, v1 snapshots) use the same grown decoder and
@ -471,9 +471,11 @@ record may have, and the derives refuse a larger one at compile time: put its
large data behind a `Vec` or a `Box`. A field of a type the derives did not
produce that is larger than that, behind a `Box` or `Vec`, is outside the
guarantee. The decoder's own frames have a fixed floor that no payload changes: at the bound a thread decodes a record of
this size from about 56 KiB in a release build and 104 KiB in a debug build, against 16 and 88 KiB for a function
of the same signature that decodes nothing, plus the caller's own frames. Stack growth was verified on
x86_64-pc-windows-msvc once, by hand, on Starfire (`decode_stack`, debug and release); later `stacker` bumps repeat it.
this size from about 56 KiB in a release build and 72 KiB in a debug build for a caller that only tests the result
(`is_ok`), plus the caller's own frames. The figure depends on how the caller holds the result: one that moves the
record out holds a second copy and needs more (about 104 KiB in debug). Stack growth was verified on
x86_64-pc-windows-msvc by hand (`decode_stack`, WINREV, 13 tests, debug and release); a `stacker` bump or a change
to the stack-size tests repeats it.
The crate does not
build for wasm32 (`fs2`), and no wasm behaviour is claimed.

View file

@ -687,9 +687,8 @@ const DECODE_STACK_SEGMENT: usize = 2 * 1024 * 1024;
/// ```
pub const MAX_RECORD_INLINE_BYTES: usize = 16 * 1024;
/// The one grown decoder of stored bytes: the stack check comes first, before any frame that holds
/// a `T`, then `serde_stacker` re-checks at every container serde's impls descend through, skipped
/// values included. No nesting bound is applied here; [`decode_payload`] walks first.
/// The one grown decoder of stored bytes: the outer stack check, then `serde_stacker` re-checks at
/// every container serde's impls descend through, skipped values included. No nesting bound is applied here; [`decode_payload`] walks first.
fn decode_grown<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> std::result::Result<T, rmp_serde::decode::Error> {
stacker::maybe_grow(DECODE_RED_ZONE, DECODE_STACK_SEGMENT, || {
let mut reader = rmp_serde::Deserializer::from_read_ref(bytes);
@ -705,10 +704,12 @@ fn decode_grown<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> std::result::Re
/// bytes. Readers of stored envelope payloads outside this crate decode through it too.
///
/// A payload inside the bound decodes on any thread that has the decoder's fixed floor, which no payload
/// changes: at the bound, about 56 KiB in release and 104 KiB in debug, against 16 and 88 KiB for a
/// same-signature function that decodes nothing, plus the caller's own frames. That holds for every
/// record the derives produce, which [`MAX_RECORD_INLINE_BYTES`] bounds. Stack growth was verified on
/// Windows once, by hand; a `stacker` bump repeats it.
/// changes: at the bound, about 56 KiB in release and 72 KiB in debug for a caller that only tests the
/// result (`is_ok`), plus the caller's own frames. The figure depends on how the caller holds the result:
/// one that moves the record out holds a second copy and needs more (about 104 KiB in debug). That holds
/// for every record the derives produce, which [`MAX_RECORD_INLINE_BYTES`] bounds. Stack growth was
/// verified on x86_64-pc-windows-msvc by hand (`decode_stack`, WINREV, 13 tests, debug and release); a
/// `stacker` bump or a change to the stack-size tests repeats it.
pub fn decode_payload<T: serde::de::DeserializeOwned>(payload: &[u8]) -> Result<T> {
check_payload_depth(payload)?;
decode_grown(payload).map_err(opaque_decode_error)