Skip to content

Modernisation plus a defensive pass on the CBOR decoder#60

Merged
rvagg merged 18 commits into
masterfrom
rvagg/upd
May 18, 2026
Merged

Modernisation plus a defensive pass on the CBOR decoder#60
rvagg merged 18 commits into
masterfrom
rvagg/upd

Conversation

@rvagg
Copy link
Copy Markdown
Collaborator

@rvagg rvagg commented May 15, 2026

Each commit is doing work here.

Decoder changes:

  • Incremental allocation in SlickReader, so length-prefixed reads grow with read progress rather than preallocating the declared length up front
  • DecodeOptions.RejectIndefinite and MaxIndefiniteSize bound indefinite-length aggregation
  • Go 1.18 fuzz harnesses for cbor and json

Strict-mode decode flags (opt-in, off by default):

  • RejectNonMinimalInteger: rejects non-minimal integer headers
  • RejectNaN, RejectInfinity: rejects non-finite floats
  • RejectNarrowFloat: rejects 16- and 32-bit float encodings

rvagg added 14 commits April 30, 2026 13:20
  - RejectIndefinite: error at the indefinite-length sigil byte
    (0x5f, 0x7f, 0x9f, 0xbf) for codecs that disallow them
    (e.g. DAG-CBOR).
  - MaxIndefiniteSize: cap on cumulative size of indefinite-length
    bytes/strings during chunk aggregation. Defaults to 32 MiB,
    matching the existing per-chunk cap.
No behaviour change beyond removing dead code and tightening a deprecated
API call.
The other suppressed checks (ST1000, ST1003, ST1016, ST1020, ST1021,
ST1022) match staticcheck's own default exclusions for stylistic
checks that aren't on by default; they are listed explicitly because
using "all" as the base reactivates them.
Reader paths now read in 4 KiB chunks rather than allocating the
full requested length up front. Numeric decode paths propagate the
matching read errors before unpacking; indefinite bytes/strings
stage each chunk through Readn for consistency with the definite
path.
Go 1.18-style fuzz harnesses for the cbor and json decoders, with
allocation/token-count invariants enforced on every input. Seed
corpora live under testdata/fuzz_corpus and include:

  - cbor: codec-fixtures (128 dag-cbor cases), RFC 7049 Appendix A
    test vectors (82), one negative case from codec-fixtures
  - json: codec-fixtures (128 dag-json cases), one negative case

Each package adds a small handcrafted seed set for edge cases.

Includes FuzzCborRoundtrip, which asserts decode/re-encode stability:
if a payload decodes without error, the first canonicalized output
and a subsequent decode+re-encode must produce identical bytes.

Also adds companion exhaustive 0/1/2-byte input tests in each
package.
Rejects CBOR heads whose integer argument is encoded in more bytes
than necessary. Applies uniformly to uints, negative ints, length
headers (bytes/strings/arrays/maps) and tag headers since all share
decodeUint.
Errors at decodeFloat when the decoded value is NaN or +/-Inf
respectively. Catches all float widths (f16/f32/f64) since the check
is on the resulting float64 value, not the wire form.
Rejects 16-bit (0xf9) and 32-bit (0xfa) float encodings at the sigil
byte, before the payload is read.
rvagg added 4 commits May 16, 2026 11:48
NewSliceReader left available-bytes at zero (always EOF). Readb tracked
the full destination buffer on short reads. Add tests for SlickReader
and TokenPump.
@rvagg rvagg merged commit e3f81f5 into master May 18, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant