Skip to content

Add NDEBUG-safe boundary checks in SnappyIOVecReader::Advance#237

Open
SongT-50 wants to merge 1 commit into
google:mainfrom
SongT-50:fix-iovec-advance-ndebug-boundary
Open

Add NDEBUG-safe boundary checks in SnappyIOVecReader::Advance#237
SongT-50 wants to merge 1 commit into
google:mainfrom
SongT-50:fix-iovec-advance-ndebug-boundary

Conversation

@SongT-50

@SongT-50 SongT-50 commented May 1, 2026

Copy link
Copy Markdown

Summary

Under NDEBUG (release builds) SnappyIOVecReader::Advance() (snappy.cc:1937) loses its
only bounds guard — a debug-only assert(total_size_remaining_ >= curr_size_remaining_).
When a caller of the raw API RawCompressFromIOVec(iov, uncompressed_length, ...) passes an
uncompressed_length larger than the actual sum of iov_len, Advance() walks curr_iov_
past the end of the iovec array (OOB read / DoS). A run of zero-length trailing entries
triggers the same walk.

The safe public wrapper CompressFromIOVec(iov, iov_cnt, ...) computes the total itself and
is unaffected — only direct raw-API callers are exposed.

Fix

Two NDEBUG-safe guards in Advance() (no assert reliance; API signature unchanged; normal
inputs take the same path):

  1. Saturate to a no-data state and return if total_size_remaining_ < curr_size_remaining_
    (prevents the unsigned underflow that leads to the past-end walk).
  2. Cap consecutive zero-length steps (kMaxEmptyWalks; 1024 is a placeholder — maintainers
    may pick a value that fits the project's convention).

Test

Three edge cases (normal / total_size > sum(iov_len) / zero-length trailing) build clean under
-fsanitize=address,undefined; a standalone repro is available on request, and I'm happy to add
a snappy_unittest case.

A permanent API-level fix (add an iov_cnt overload and deprecate the 3-arg raw API) is the
cleaner direction — happy to follow up if you prefer that instead of / in addition to this interim guard.

@google-cla

google-cla Bot commented May 1, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@SongT-50
SongT-50 force-pushed the fix-iovec-advance-ndebug-boundary branch from de1899c to 4be8f6f Compare May 1, 2026 08:14
@SongT-50

SongT-50 commented Jul 6, 2026

Copy link
Copy Markdown
Author

Hi — a gentle ping on this PR. I know maintainers are busy, so no rush at all. If there's anything I can do to help it move forward (rebase, extra tests, or clarifying the boundary-check rationale), I'm happy to. Thanks for maintaining snappy!

The current Advance() relies on a debug-only assert to enforce the invariant
total_size_remaining_ >= curr_size_remaining_. Under NDEBUG (most production
builds) the assert is stripped, leaving the inner do-while loop unguarded
against caller-misuse of the raw API RawCompressFromIOVec(iov,
uncompressed_length, ...) when uncompressed_length does not match the actual
sum of iov_len values.

Two defensive checks are added (interim, NDEBUG-safe):

 1. If total_size_remaining_ < curr_size_remaining_ on entry, saturate to
    no-data state and bail out rather than underflowing total_size_remaining_
    into a large unsigned value below.

 2. Cap consecutive zero-length iovec walks at kMaxEmptyWalks (1024). A run
    of zero-length trailing entries with nonzero claimed total_size would
    otherwise spin past the array end via the do-while loop.

The default safe wrapper CompressFromIOVec(iov, iov_cnt, ...) already
computes the total itself before calling the raw API and is unaffected by
this change. The patch is backward compatible (API signature unchanged).

A more permanent API-level fix is to add a safe overload of
RawCompressFromIOVec that takes iov_cnt explicitly and deprecate the current
3-arg form. Happy to prepare a follow-up PR for that direction if
maintainers prefer.

Findings cross-verified through independent code auditing (multi-model code
review pipeline).
@SongT-50
SongT-50 force-pushed the fix-iovec-advance-ndebug-boundary branch from 4be8f6f to 87425bc Compare July 6, 2026 15:02
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.

1 participant