Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/compress/zstdmt_compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,11 @@ static void ZSTDMT_compressionJob(void* jobDescription)
if (ZSTD_isError(hSize)) JOB_ERROR(hSize);
DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize);
ZSTD_invalidateRepCodes(cctx);
/* ZSTD_compressBegin() sets isFirstBlock=1 for every job, but only the
* frame's first block must skip RLE to stay compatible with decoders
* <= v1.4.3. Without this, the first block of each job is emitted as a
* regular compressed block instead of an RLE block. */
cctx->isFirstBlock = 0;
}

/* compress the entire job by smaller chunks, for better granularity */
Expand Down
30 changes: 30 additions & 0 deletions tests/fuzzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4325,6 +4325,36 @@ static int basicUnitTests(U32 const seed, double compressibility)
DISPLAYLEVEL(3, "OK \n");
}

/* The RLE guard must only skip the frame's first block, not the first
* block of every multithreaded job (issue #4457). */
{ size_t const srcSize = 2 MB;
size_t const jobSize = 512 KB;
size_t singleSize;
size_t mtSize;
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
DISPLAYLEVEL(3, "test%3i : RLE detection in multithreaded jobs : ", testNb++);
if (cctx == NULL) goto _output_error;
memset(CNBuffer, 0, srcSize);
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, 1) );
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 0) );
singleSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, srcSize);
if (ZSTD_isError(singleSize)) goto _output_error;
CHECK_Z( ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters) );
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, 1) );
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 2) );
CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_jobSize, (int)jobSize) );
mtSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, srcSize);
if (ZSTD_isError(mtSize)) goto _output_error;
if (mtSize != singleSize) {
DISPLAYLEVEL(4, "error: MT cSize %u != single-thread cSize %u ! \n", (unsigned)mtSize, (unsigned)singleSize);
goto _output_error;
}
{ CHECK_NEWV(regenSize, ZSTD_decompress(decodedBuffer, srcSize, compressedBuffer, mtSize));
if (regenSize != srcSize) goto _output_error; }
ZSTD_freeCCtx(cctx);
DISPLAYLEVEL(3, "OK \n");
}

DISPLAYLEVEL(3, "test%3i : ZSTD_generateSequences decode from sequences test : ", testNb++);
{
size_t srcSize = 150 KB;
Expand Down