Skip to content

compress: fix input left pending with ZSTD_c_stableInBuffer - #4943

Merged
Cyan4973 merged 3 commits into
devfrom
fix-4868-stablein-reset
Nov 12, 2026
Merged

Cyan4973 merged 3 commits into
devfrom
fix-4868-stablein-reset

Conversation

@Cyan4973

Copy link
Copy Markdown
Contributor

Fixes #4868, reported by @IlyaGrebnov.

With ZSTD_c_stableInBuffer, ZSTD_compressStream2() with ZSTD_e_continue can leave less than one block of input pending (stableIn_notConsumed), before or after compression has started. This PR fixes three problems with that pending input, one commit each:

  1. ZSTD_CCtx_reset() did not clear it. After an abandoned frame, the next frame started that many bytes before the new input buffer. It read up to 128 KB out of bounds, and the frame contained those bytes. ZSTD_compress2() was affected too, because it starts with a session reset.
  2. The stable buffer was checked against the pending input only when the call kept the input pending. A call that started compression (with ZSTD_e_flush, ZSTD_e_end, or a full block) skipped the check. A different src pointer then caused the same out-of-bounds read, instead of stabilityCondition_notRespected. Disabling ZSTD_c_stableInBuffer while input was pending silently dropped that input from the frame; this is now rejected.
  3. ZSTD_flushStream() and ZSTD_endStream() failed with srcSize_wrong on pending input when the previous frame of the context did not use ZSTD_c_stableInBuffer, for example on a new context.

Each commit adds a test to zstreamtest that fails without it.

Only programs that set ZSTD_c_stableInBuffer (experimental API) reach these paths. The pending-input logic was added in c1668a0, first released in v1.5.4.

With ZSTD_c_stableInBuffer, ZSTD_compressStream2() with ZSTD_e_continue
can leave less than one block of input pending, counted in
stableIn_notConsumed, before or after compression has started.
ZSTD_CCtx_reset() did not clear it, so after an abandoned frame, the next
frame started that many bytes before the new input buffer: it read out of
bounds, and the frame contained those bytes. ZSTD_compress2() was affected
too, since it starts with a session reset.

Fixes #4868
The stable input buffer was checked against the pending input only when
the call kept the input pending. A call that started compression, with
ZSTD_e_flush, ZSTD_e_end or a full block of input, skipped the check. A
different src pointer then made compression read before it, instead of
failing with stabilityCondition_notRespected as documented.

Disabling ZSTD_c_stableInBuffer while input is pending is now rejected
too: that input was silently missing from the frame.
…stable input

While input is pending before the first block, the parameters of the frame
are not applied yet. inBuffer_forEndFlush() relied on them, so on a context
whose previous frame did not use ZSTD_c_stableInBuffer, such as a new one,
it passed an empty input instead of the stable buffer, and the frame failed
with srcSize_wrong.
@Cyan4973
Cyan4973 force-pushed the fix-4868-stablein-reset branch from 82bd60e to c55665a Compare November 12, 2026 21:28
@Cyan4973 Cyan4973 added the bug label Nov 12, 2026
@Cyan4973
Cyan4973 merged commit 5cfc430 into dev Nov 12, 2026
113 checks passed
@Cyan4973
Cyan4973 deleted the fix-4868-stablein-reset branch November 13, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ZSTD_CCtx_reset(session_only) keeps pending stable input: next frame reads before the caller's buffer

2 participants