Skip to content

fix(http): count batch orders without copying or over-reading the body - #67

Merged
Reddimus merged 1 commit into
mainfrom
fix/rate-limit-batch-count
Sep 25, 2026
Merged

Reddimus merged 1 commit into
mainfrom
fix/rate-limit-batch-count

Conversation

@Reddimus

Copy link
Copy Markdown
Owner

Summary

RateLimitedTransport counts a batch's orders by reading the request body as JSON, and it read past the end of that body. It used Glaze's default options, which assume a null terminator follows the text, on a std::string_view that promises no such thing. A view over the start of a longer buffer was counted from the bytes after it, and a truncated body at the end of its buffer was read one byte beyond it. Counting also copied every order into a string just to count it.

  • The count now reads into std::vector<glz::skip> with null_terminated = false, so it stays inside the view and stores nothing per order. This works with Glaze 8.3 and 9.0.
  • Every valid body counts the same as before. A truncated or malformed body still costs one unit.
  • RateLimitedTransport::cost() and request() both change; nothing else does.

Closes #66

Benchmarks

BM_RateLimitCost/20 counts a 20-order batch. Main (15ff8ca) against this branch; heap counts are exact, and instructions come from the suite's macOS counter, which varies by well under 1% between runs even on a loaded machine.

Measure macOS, Apple Clang 21 (libc++) Ubuntu 24.04, GCC 13 (libstdc++)
Allocations 26 → 6 (−77%) 26 → 6 (−77%)
Bytes allocated 5,992 → 63 (−99%) 6,433 → 63 (−99%)
Instructions 24,040 → 13,556 (−44%) n/a

BM_SerializeBatchCreate and every other benchmark are unchanged. This runs once per batch order request, before it goes out.

Checks

  • make format lint test (macOS, 284/284)
  • make sanitize (macOS, 275/275) and ./tools/test_consumers.sh
  • Ubuntu 24.04, GCC 13 with -DKALSHI_WARNINGS_AS_ERRORS=ON -DKALSHI_BUILD_BENCHMARKS=ON: 284/284 and the benchmark smoke run. make tidy with clang 18 and libc++ is clean.
  • New tests that fail on main: CountsOnlyTheBodyItIsGiven (a prefix view counts 2 orders on main), CountsBatchItemsWithoutReadingPastTheBody (ASan catches the one-byte over-read), and AllocationBudget.CountingABatchDoesNotCopyItsOrders (26 against 6 allocations). CountsBatchItemsWhateverTheyContain covers quotes, brackets, and nesting inside orders.
  • An independent review ran 55 valid, empty, truncated, and malformed bodies against Glaze 8.3 and 9.0: every valid body counts as before, and the only difference is that a few invalid bodies such as {"orders":[1 2,3]} now count their elements instead of falling back to one.
  • CHANGELOG.md updated under [Unreleased]
  • SemVer impact: patch

Copilot AI lite review requested due to automatic review settings September 25, 2026 20:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Reddimus
Reddimus merged commit 9c1b412 into main Sep 25, 2026
14 checks passed
@Reddimus
Reddimus deleted the fix/rate-limit-batch-count branch September 25, 2026 21:21
@Reddimus Reddimus mentioned this pull request Sep 25, 2026
4 tasks done
Reddimus added a commit that referenced this pull request Sep 25, 2026
## Summary

Releases 0.6.2: sets the CMake version, moves the `[Unreleased]` notes
into a `[0.6.2]` section, adds its compare links, and points the
README's FetchContent example at `v0.6.2`.

0.6.2 contains #65 (allocation and instruction counters in the
benchmarks, with realistic fixtures), #67 (`RateLimitedTransport` stays
inside the batch body and no longer copies each order: 26 allocations
down to 6 for 20 orders), and #68 (SIGPIPE protection, macOS build
fixes, and the shorter README). No public API changes.

After this merges, tagging `v0.6.2` on the merge commit runs
`release.yml`. It checks the tag against the CMake version and the
CHANGELOG section, waits for CI on that commit, publishes the release,
and dispatches the API reference deploy to GitHub Pages.

## Checks

- [x] `tools/project_version.sh` prints 0.6.2
- [x] `release.yml`'s extraction of the `[0.6.2]` section yields the
notes
- [x] `make lint-docs` and `./tools/test_consumers.sh` pass
- [x] SemVer impact: this is the 0.6.2 patch release
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.

RateLimitedTransport reads past the end of a batch body

2 participants