github iskorotkov/avro v2.33.0

5 hours ago

Release notes — v2.33.0

Highlights

  • Hardening against malicious payloads — new MaxMapAllocSize config, 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 TextMarshaler keys — ~12% faster with ~25% fewer allocations by dropping redundant []bytestring conversions 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 and TextUnmarshaler-keyed decoders, closing a chunking-bypass gap.
  • feat: fail fast in read callback loop (codec_skip.go) — Skip aborts 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 and reflect2.UnsafeGetIndex for plain primitive elements. Apple M4 Pro, geomean −16.6%:

    • ArrayDecode_Float64/n=1000 2.275µs → 1.006µs (−55.8%)
    • ArrayDecode_Float32/n=1000 2.082µs → 0.921µs (−55.8%)
    • ArrayDecode_Int64/n=1000 2.942µs → 2.648µs (−10.0%)
    • ArrayDecode_String/n=1000 7.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) — decode ReadBytes straight into UnmarshalText, encode WriteBytes straight from MarshalText. Decode: −12% time, −25% allocs; encode: −10% time.

Fixes

  • prevent integer overflow — int-overflow hardening across ReadBlockHeader, 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 remaining int64 → int narrowing sites:
    • union index in reader_generic.go1<<32 previously truncated to 0 and silently selected types[0] on 32-bit.
    • readBytes — positive truncation let lengths above Config.MaxByteSliceSize slip past the cap on 32-bit.
    • ocf/ocf.go readBlockmake([]byte, size) panicked on negative size everywhere and on size > MaxInt on 32-bit, giving a process-crash primitive instead of a clean error.
  • 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 bypass MaxSliceAllocSize / MaxMapAllocSize.
  • test(skip): allow ReadBlockHeader rejection on 32-bit for huge-skip EOF testsTestDecoder_Skip{Array,Map}EOF now accept either EOF or the new "block length is too big" error so the suite passes under GOARCH=386.

Chore / CI

  • New test-386 job runs go test ./... with GOARCH=386 and CGO_ENABLED=0 (-race requires 64-bit and is omitted). Three tests with untyped 2147483648 constants are split into *_64bit_test.go siblings gated by //go:build amd64 || arm64 || ….
  • chore(tools): pin golangci-lint and gotestsum via go.mod tool directive — declared via Go 1.24's tool directive (golangci-lint v2.8.0, gotestsum v1.13.0) and invoked through go tool … from Make and CI. Removes the golangci-lint-action and action-gotestsum actions and any reliance on a pre-installed binary on PATH. go directive bumped to 1.24.13; testify pulled to v1.11.1.

Notes for users

  • No public API removals. New MaxMapAllocSize config field is opt-in and falls back to existing defaults when zero.
  • 32-bit (GOARCH=386, arm, etc.) consumers get tighter bounds checking on Avro long values used as lengths/indices — payloads that previously silently truncated now surface a clean "is too big" error.
  • Contributors no longer need separate golangci-lint / gotestsum installs; make lint / make test invoke them via go tool.

Full changelog: git log v2.32.0..v2.33.0

Don't miss a new avro release

NewReleases is sending notifications on new releases.