Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Makes
fromFlattysafe to run on untrusted/hostile bytes (e.g. packets off the wire). Today a malformed blob can take the whole process down; after this PR a bad blob fails with a catchable error instead of a segfault, an out-of-memory abort, or a stack overflow. Adds a fuzzer that proves it.Why
fromFlattyis commonly used to decode network data, but the decode path trusted its input: unchecked reads, unchecked length/count prefixes driving allocations,cast-ed enum discriminators, and unbounded recursion. A fuzzer (see below) found 178 hard aborts across every length-prefixed and variant type — each one a remotely triggerable crash.The fuzzer (
tests/fuzz.nim)Feeds truncated, oversized, and randomly-mutated blobs to the decode path across every type shape and asserts none of them crash the process (a catchable error is fine). Because a bad input can hard-abort, each child decode runs in a subprocess that checkpoints its input first — so an uncatchable abort is reported with a replayable reproducer instead of killing the run. Deterministic (seeded), so every finding replays.
The hardening
binny): truncated blobs can't over-read; stays on even under-d:danger.new(x, badTag).ref/seqchain) before it overflows the thread stack — no per-call depth counter, no bookkeeping to unwind. Guards only the four heap-indirection procs (ref/seq/Table/Set), which every type cycle must pass through, so object/tuple/array stay untouched.Decode failures raise
FlattyError(bad length/count/enum) orIndexDefect(truncation); catch both.Performance
tests/bench_flatty_types.nim,-d:release, best-of-5. Serialize is unchanged (no checks added there). Deserialize:copyMem.The stack guard and the Table prealloc cap add no measurable cost on normal data.