Skip to content

compress: fix ZSTD_CCtx_refThreadPool() rebinding and shared pool resizing - #4917

Merged
Cyan4973 merged 2 commits into
devfrom
thread-pool-rebind
Nov 10, 2026
Merged

Cyan4973 merged 2 commits into
devfrom
thread-pool-rebind

Conversation

@Cyan4973

Copy link
Copy Markdown
Contributor

Two fixes for a thread pool given with ZSTD_CCtx_refThreadPool().

ZSTD_CCtx_refThreadPool() only changed cctx->pool. Once created, the multi-threaded context kept the pool it was created with, so the next frames still ran on the previous pool, including after ZSTD_CCtx_refThreadPool(cctx, NULL). If the application then freed the previous pool, the next frame used freed memory. ZSTD_CCtx_refThreadPool() now frees the multi-threaded context when the pool changes, and the next frame creates one with the new pool. This relies on #4871: the pool can only change between frames, and ZSTDMT_freeCCtx() now waits for the jobs of an abandoned frame.

When ZSTD_c_nbWorkers changed between two frames, ZSTDMT_resize() called POOL_resize() even on a pool given with ZSTD_CCtx_refThreadPool(). One context could then change the number of threads of a pool shared with other contexts, although such a pool is meant to limit them. A provided pool now keeps its size, as it already did when the multi-threaded context is created.

zstd.h now states both behaviors.

Tests: a new thread pool test in fuzzer.c moves a context from a pool to another, then to an internal pool, and frees the previous pool each time. It also changes ZSTD_c_nbWorkers on a shared pool. Without the first fix, AddressSanitizer reports a heap-use-after-free in POOL_tryAdd(). Without the second, the size of the shared pool changes.

@meta-cla meta-cla Bot added the CLA Signed label Nov 10, 2026
@Cyan4973 Cyan4973 self-assigned this Nov 10, 2026
ZSTD_CCtx_refThreadPool() only changed cctx->pool. Once created, the
MT context kept the pool it was created with, so the next frames still
ran on the previous pool, including after ZSTD_CCtx_refThreadPool(cctx,
NULL). If the caller then freed the previous pool, the next frame used
freed memory.

ZSTD_CCtx_refThreadPool() now frees the MT context when the pool
changes, and the next frame creates one with the new pool. The pool can
only change between frames, and ZSTDMT_freeCCtx() waits for the jobs of
an abandoned frame.
When ZSTD_c_nbWorkers changed between two frames, ZSTDMT_resize()
called POOL_resize() on the context's pool, even on a pool given with
ZSTD_CCtx_refThreadPool(). One context could then change the number of
threads of a pool shared with other contexts, although such a pool is
meant to limit them.

ZSTDMT_createCCtx_advanced() already leaves a provided pool unchanged.
ZSTDMT_resize() now does the same.
@Cyan4973
Cyan4973 merged commit c2095c7 into dev Nov 10, 2026
110 checks passed
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.

1 participant