Skip to content

decoder: add MaxOutputBytes decode option#22

Merged
tamirms merged 7 commits into
masterfrom
reduce-allocations
Mar 12, 2026
Merged

decoder: add MaxOutputBytes decode option#22
tamirms merged 7 commits into
masterfrom
reduce-allocations

Conversation

@tamirms
Copy link
Copy Markdown

@tamirms tamirms commented Mar 11, 2026

Summary

  • Add MaxOutputBytes field to DecodeOptions that tracks cumulative decoded output size across a single decode operation and aborts if the limit is exceeded
  • Add TrackOutputBytes method and TrackOutputBytesOf[T] generic helper for generated code to call before each allocation
  • Cap array pre-allocation at 256 elements, growing via append beyond that, to keep memory proportional to data actually decoded
  • Track allocations in DecodeFixedOpaque, decodeArray, decodeUnion, decodeMap, and allocPtrIfNil
  • Bump minimum Go version to 1.25 for generics support

Test plan

  • Existing xdr3 test suite passes
  • New TestMaxOutputBytes covers: unlimited (no limit), exceeded (aborts), not_reached (succeeds)

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 11, 2026 17:35
@tamirms tamirms force-pushed the reduce-allocations branch 2 times, most recently from 19bd55b to bc50d72 Compare March 11, 2026 17:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an output-size accounting mechanism to the xdr3 decoder to mitigate memory amplification during decoding, along with stress-style tests intended to validate the fix and concurrency behavior.

Changes:

  • Introduces DecodeOptions.MaxOutputBytes and decoder-side byte tracking (TrackOutputBytes, TrackOutputBytesOf[T]) to bound decoded output allocations.
  • Modifies slice decoding to cap initial pre-allocation (256) and grow via append for large arrays.
  • Adds a new test suite covering the preallocation amplification scenario and MaxOutputBytes behavior; bumps the module’s Go version.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
xdr3/decode.go Adds MaxOutputBytes tracking, new tracking helpers, and changes array/map/union/pointer allocation behavior.
xdr3/prealloc_vulnerability_test.go Adds tests intended to demonstrate the prior amplification issue, plus MaxOutputBytes/concurrency coverage.
go.mod Updates the go directive to 1.25.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread xdr3/decode.go
Comment thread xdr3/decode.go Outdated
Comment thread xdr3/decode.go
Comment thread xdr3/decode.go Outdated
@tamirms tamirms force-pushed the reduce-allocations branch 3 times, most recently from f3572dd to 112f917 Compare March 11, 2026 17:53
@tamirms tamirms requested a review from Copilot March 11, 2026 17:58
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread xdr3/decode.go Outdated
Comment thread xdr3/decode.go Outdated
Comment thread go.mod
Comment thread xdr3/decode_limits_test.go
Comment thread xdr3/decode_limits_test.go
Comment thread xdr3/decode_limits_test.go
Comment thread xdr3/decode.go Outdated
Comment thread xdr3/decode.go Outdated
Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #23, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #24, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #25, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #26, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #27, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #28, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #29, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown

Copilot AI commented Mar 11, 2026

@tamirms I've opened a new pull request, #30, to work on those changes. Once the pull request is ready, I'll request review from you.

… limits

Add a MaxOutputBytes field to DecodeOptions that tracks cumulative
decoded output size across a single decode operation. Before each
allocation (array element, union arm, optional field, opaque data),
the size is added to a running total; if it exceeds MaxOutputBytes
the decode is aborted with ErrOutputBytesExceeded.

Key changes:
- Add TrackOutputBytes method and TrackOutputBytesOf[T] generic helper
- Cap array pre-allocation at 256 elements, growing via append beyond that
- Track allocations in DecodeFixedOpaque, decodeArray, decodeUnion,
  decodeMap, and allocPtrIfNil
- Bump minimum Go version to 1.25 for generics support

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@tamirms tamirms force-pushed the reduce-allocations branch from 112f917 to c677e1b Compare March 11, 2026 18:52
@tamirms tamirms requested a review from a team March 11, 2026 19:24
Comment thread xdr3/decode.go
Copy link
Copy Markdown
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something of interest to me is that this ties a successful decode to the implementation of Go. Since it tracks the size of the Go objects in memory if that max is set very tight, a change in the Go compiler and how it structures memory will impact if a decode is inside or outside of the configured max. Even building on one host operating system may produce a different value to another.

Will this be configured pretty high with a lot of buffer?

Comment thread xdr3/decode.go Outdated
Copy link
Copy Markdown
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

@tamirms
Copy link
Copy Markdown
Author

tamirms commented Mar 12, 2026

Will this be configured pretty high with a lot of buffer?

The limits in soroban-rpc will be set with significant headroom — 4KB for getLedgerEntries where legitimate data is a few hundred bytes, 1MB for sendTransaction where a valid envelope is typically well under 100KB

The old name was ambiguous — it could refer to wire output, serialized
bytes, etc. MaxDecodedSize makes it clear this tracks the cumulative
in-memory size (unsafe.Sizeof) of Go objects created during decoding.

Also renames the internal fields and error sentinel to match:
  maxOutputBytes → maxDecodedSize
  outputBytes → decodedSize
  ErrOutputBytesExceeded → ErrDecodedSizeExceeded

TrackOutputBytes/TrackOutputBytesOf function names are left unchanged
since they are called by xdrgen-generated code.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Comment thread xdr3/decode.go
MaxMemoryBytes more clearly communicates that this limits the cumulative
in-memory size of Go objects allocated during decoding.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Comment thread xdr3/decode.go Outdated
tamirms and others added 2 commits March 12, 2026 14:38
Add an aggregate complete job that depends on all build matrix jobs.
This provides a stable status check name that doesn't change when Go
versions are bumped, allowing branch protection to reference complete
instead of version-specific Build (X.Y) checks.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Comment thread .github/workflows/build.yml Fixed
Address CodeQL security finding by adding explicit permissions
block to limit the workflow token to contents: read.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@tamirms tamirms merged commit cc2b061 into master Mar 12, 2026
8 checks passed
@tamirms tamirms deleted the reduce-allocations branch March 12, 2026 22:58
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.

7 participants