diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 325f0b54dfc..0fb5eeffbba 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1947,6 +1947,10 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) { if ( (reset == ZSTD_reset_session_only) || (reset == ZSTD_reset_session_and_parameters) ) { + /* A prefix is only used once : if a frame was started, it is abandoned now, + * so the prefix must not leak into the next frame */ + if (dctx->streamStage != zdss_init && dctx->dictUses == ZSTD_use_once) + ZSTD_clearDict(dctx); dctx->streamStage = zdss_init; dctx->noForwardProgress = 0; dctx->isFrameDecompression = 1; diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 88a20a3e270..39a21a434b8 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1406,6 +1406,39 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests) DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); } + DISPLAYLEVEL(3, "test%3i : prefix is dropped by session reset after a rejected frame header : ", testNb++); + { BYTE const badHeader[6] = { 0x28, 0xB5, 0x2F, 0xFD, 0x08, 0x00 }; /* reserved bit set */ + CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) ); + outBuff.dst = decodedBuffer; + outBuff.size = CNBufferSize; + outBuff.pos = 0; + inBuff.src = badHeader; + inBuff.size = sizeof(badHeader); + inBuff.pos = 0; + if (!ZSTD_isError(ZSTD_decompressStream(zd, &outBuff, &inBuff))) goto _output_error; + CHECK_Z( ZSTD_DCtx_reset(zd, ZSTD_reset_session_only) ); + outBuff.pos = 0; + inBuff.src = compressedBuffer; + inBuff.size = cSize; + inBuff.pos = 0; + if (!ZSTD_isError(ZSTD_decompressStream(zd, &outBuff, &inBuff))) goto _output_error; /* prefix must be gone */ + CHECK_Z( ZSTD_DCtx_reset(zd, ZSTD_reset_session_only) ); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3i : prefix survives session reset before any input : ", testNb++); + CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) ); + CHECK_Z( ZSTD_DCtx_reset(zd, ZSTD_reset_session_only) ); + outBuff.dst = decodedBuffer; + outBuff.size = CNBufferSize; + outBuff.pos = 0; + inBuff.src = compressedBuffer; + inBuff.size = cSize; + inBuff.pos = 0; + CHECK_Z( ZSTD_decompressStream(zd, &outBuff, &inBuff) ); + if (outBuff.pos != CNBufferSize) goto _output_error; /* must regenerate whole input */ + DISPLAYLEVEL(3, "OK \n"); + DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compressStream2 : ", testNb++); outBuff.dst = compressedBuffer; outBuff.size = compressedBufferSize;