Release notes — v2.33.0
Highlights
- Hardening against malicious payloads — new
MaxMapAllocSizeconfig, cumulative allocation enforcement across blocks for both maps and slices, and int-overflow fixes that close process-crash and bypass primitives on 32-bit builds. - Faster scalar array decode — up to ~56% faster (Float32/Float64) and ~10% faster for Int64 by removing per-element interface dispatch.
- Faster map decode for
TextMarshalerkeys — ~12% faster with ~25% fewer allocations by dropping redundant[]byte↔stringconversions on the key path.
Features
feat(map): add MaxMapAllocSize config with cumulative enforcement(config.go,codec_map.go) — caps cumulative map allocation across chunked blocks for both string-keyed andTextUnmarshaler-keyed decoders, closing a chunking-bypass gap.feat: fail fast in read callback loop(codec_skip.go) —Skipaborts on the first inner read error (#4, @klajok).
Performance
-
perf(array): scalar element fast-path for array decoder(codec_array_scalar.go) — skips per-element interface dispatch andreflect2.UnsafeGetIndexfor plain primitive elements. Apple M4 Pro, geomean −16.6%:ArrayDecode_Float64/n=10002.275µs → 1.006µs (−55.8%)ArrayDecode_Float32/n=10002.082µs → 0.921µs (−55.8%)ArrayDecode_Int64/n=10002.942µs → 2.648µs (−10.0%)ArrayDecode_String/n=10007.564µs → 7.183µs (−5.0%)
Wire format and alloc count unchanged.
-
perf(map): drop redundant []byte<->string conversions in TextMarshaler key path(codec_map.go) — decodeReadBytesstraight intoUnmarshalText, encodeWriteBytesstraight fromMarshalText. Decode: −12% time, −25% allocs; encode: −10% time.
Fixes
prevent integer overflow— int-overflow hardening acrossReadBlockHeader, array/map cumulative size checks, and skip helpers (#9, @klajok).fix: complete int-overflow hardening(reader.go,reader_generic.go,ocf/ocf.go) — closes three remainingint64 → intnarrowing sites:- union index in
reader_generic.go—1<<32previously truncated to0and silently selectedtypes[0]on 32-bit. readBytes— positive truncation let lengths aboveConfig.MaxByteSliceSizeslip past the cap on 32-bit.ocf/ocf.goreadBlock—make([]byte, size)panicked on negative size everywhere and onsize > MaxInton 32-bit, giving a process-crash primitive instead of a clean error.
- union index in
fix(map): cap allocation cumulatively across blocks— slice and map decoders track running totals so a producer can no longer chunk a large collection into sub-limit blocks to bypassMaxSliceAllocSize/MaxMapAllocSize.test(skip): allow ReadBlockHeader rejection on 32-bit for huge-skip EOF tests—TestDecoder_Skip{Array,Map}EOFnow accept either EOF or the new "block length is too big" error so the suite passes underGOARCH=386.
Chore / CI
- New
test-386job runsgo test ./...withGOARCH=386andCGO_ENABLED=0(-racerequires 64-bit and is omitted). Three tests with untyped2147483648constants are split into*_64bit_test.gosiblings gated by//go:build amd64 || arm64 || …. chore(tools): pin golangci-lint and gotestsum via go.mod tool directive— declared via Go 1.24'stooldirective (golangci-lint v2.8.0,gotestsum v1.13.0) and invoked throughgo tool …from Make and CI. Removes thegolangci-lint-actionandaction-gotestsumactions and any reliance on a pre-installed binary onPATH.godirective bumped to 1.24.13; testify pulled to v1.11.1.
Notes for users
- No public API removals. New
MaxMapAllocSizeconfig field is opt-in and falls back to existing defaults when zero. - 32-bit (
GOARCH=386,arm, etc.) consumers get tighter bounds checking on Avrolongvalues used as lengths/indices — payloads that previously silently truncated now surface a clean "is too big" error. - Contributors no longer need separate
golangci-lint/gotestsuminstalls;make lint/make testinvoke them viago tool.
Full changelog: git log v2.32.0..v2.33.0