]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
[zstdmt] Fix bug where extra empty blocks are emitted
authorNick Terrell <terrelln@fb.com>
Tue, 6 Oct 2020 00:37:19 +0000 (17:37 -0700)
committerNick Terrell <terrelln@fb.com>
Mon, 12 Oct 2020 19:55:17 +0000 (12:55 -0700)
When zstdmt cannot get a buffer and `ZSTD_e_end` is passed an empty
compression job can be created. Additionally, `mtctx->frameEnded` can be
set to 1, which could potentially cause problems like unterminated blocks.

The fix is to adjust to `ZSTD_e_flush` even when we can't get a buffer.

lib/compress/zstdmt_compress.c
tests/zstreamtest.c

index 6f3e06229769dce8fcb042059a8142568ca58372..98c4ce0bbb1d5faf41977f95252d968fc98ec4fe 100644 (file)
@@ -1773,8 +1773,16 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
             mtctx->inBuff.filled += syncPoint.toLoad;
             forwardInputProgress = syncPoint.toLoad>0;
         }
-        if ((input->pos < input->size) && (endOp == ZSTD_e_end))
-            endOp = ZSTD_e_flush;   /* can't end now : not all input consumed */
+    }
+    if ((input->pos < input->size) && (endOp == ZSTD_e_end)) {
+        /* Can't end yet because the input is not fully consumed.
+            * We are in one of these cases:
+            * - Input buffer is NULL & empty
+            * - We filled the input buffer
+            * - We hit a synchronization point
+            */
+        assert(mtctx->inBuff.filled == 0 || mtctx->inBuff.filled == mtctx->targetSectionSize || mtctx->params.rsyncable);
+        endOp = ZSTD_e_flush;
     }
 
     if ( (mtctx->jobReady)
index e4b9f0dec3109e4be71c6327d82c3f7d969c2124..13c1530cd80d383114ad21b893009a071dc850aa 100644 (file)
@@ -2048,7 +2048,11 @@ static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
                     }
                 }
                 /* Enable rsyncable mode 1 in 4 times. */
-                setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, (FUZ_rand(&lseed) % 4 == 0), opaqueAPI);
+                {
+                    int const rsyncable = (FUZ_rand(&lseed) % 4 == 0);
+                    DISPLAYLEVEL(5, "t%u: rsyncable : %d \n", testNb, rsyncable);
+                    setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, rsyncable, opaqueAPI);
+                }
 
                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );