Skip to content

Fix unsigned underflow in BrotliBinaryDiff::Diff() reserve size. - #274

Merged
garretrieger merged 1 commit into
w3c:mainfrom
studio-design:fix_diff_reserve_underflow
Oct 9, 2026
Merged

garretrieger merged 1 commit into
w3c:mainfrom
studio-design:fix_diff_reserve_underflow

Conversation

@sharapeco

Copy link
Copy Markdown
Contributor

Problem

BrotliBinaryDiff::Diff() reserves the output buffer based on the size difference:

sink.reserve(2 * (font_derived.size() - font_base.size()));

FontData::size() returns unsigned int, so when the derived data is smaller than the base (e.g. a table-keyed patch that shrinks a table), the subtraction wraps around. A 103-byte shrink requests reserve(4294967090) (~4 GiB). With memory overcommit this goes unnoticed because the pages are never touched. Under a hard memory limit (e.g. a 4 GiB container) font2ift aborts with std::bad_alloc.

Fix

Reserve only when the derived data is larger, and compute in size_t:

size_t base_size = font_base.size();
size_t derived_size = font_derived.size();
if (derived_size > base_size) {
  sink.reserve(2 * (derived_size - base_size));
}

The reserve is only a capacity hint, so the generated patch bytes are unchanged.

Test

Added BrotliPatchingTest.DiffAndPatchWithSmallerDerived, which diffs full Roboto against a subset and checks the patch round-trips. On hosts with overcommit the old code doesn't fail this test (the oversized reservation succeeds), so it covers the shrinking path rather than reproducing the crash.

🤖 Generated with Claude Code

When derived font is smaller than base font, the unsigned subtraction
wraps around 2^32, requesting a ~4 GiB allocation. This fails on
memory-constrained environments like Cloud Run (4 GiB) with
std::bad_alloc.

Fix: reserve only when derived size exceeds base size. Promote sizes
to size_t to avoid wrap-around during multiplication.

Add regression test: DiffAndPatchWithSmallerDerived exercises the
smaller-than-base code path.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@garretrieger
garretrieger merged commit 5967805 into w3c:main Oct 9, 2026
3 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.

2 participants