From edc5a11757ae10ce6663661ae847e9335084135e Mon Sep 17 00:00:00 2001 From: ddidderr Date: Mon, 20 Jul 2026 02:23:26 +0200 Subject: [PATCH] fix(mt): keep projected job snapshots under mutex The Rust-owned frame-progression ring scan consumes ZSTDMT_jobProjection through ZSTDMT_projectJob. That callback previously copied counters under job_mutex but read source and prefix metadata after unlocking. Keep the complete projection in one mutex-protected snapshot, matching the original ZSTDMT_getFrameProgression access pattern without moving descriptor or synchronization ownership out of C. Test Plan: - `rustfmt --check --edition 2021 rust/src/zstdmt_compress.rs` -- passed. - `git diff --check` and `git diff --cached --check` -- passed. - Static inspection only; no cargo, make, native binaries, tests, fuzzers, or heavyweight commands were run. --- lib/compress/zstdmt_compress.c | 4 ++-- rust/src/zstdmt_compress.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 3808861e7..157b43b7e 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -1703,12 +1703,12 @@ static void ZSTDMT_projectJob(void* opaque, unsigned jobID, ZSTD_pthread_mutex_lock(&job->job_mutex); projection->consumed = job->consumed; projection->cSize = job->cSize; - projection->dstFlushed = job->dstFlushed; - ZSTD_pthread_mutex_unlock(&job->job_mutex); projection->srcStart = job->src.start; projection->srcSize = job->src.size; projection->prefixStart = job->prefix.start; projection->prefixSize = job->prefix.size; + projection->dstFlushed = job->dstFlushed; + ZSTD_pthread_mutex_unlock(&job->job_mutex); } static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem) diff --git a/rust/src/zstdmt_compress.rs b/rust/src/zstdmt_compress.rs index 1924a0e56..b4c920331 100644 --- a/rust/src/zstdmt_compress.rs +++ b/rust/src/zstdmt_compress.rs @@ -664,8 +664,8 @@ pub type ZSTDMT_bufferGetFn = unsafe extern "C" fn(*mut c_void) -> ZstdMtBuffer; /// Scalar snapshot of one C-owned job descriptor. /// -/// The C adapter fills this projection while holding the descriptor mutex. -/// Rust owns only the ring-scan decisions below; the descriptor layout, +/// The C adapter fills the complete projection while holding the descriptor +/// mutex. Rust owns only the ring-scan decisions below; the descriptor layout, /// synchronization objects, and all pointer ownership stay in C. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]