]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
added fuzzer test for compressSequencesAndLiterals()
authorYann Collet <cyan@fb.com>
Tue, 24 Dec 2024 02:42:51 +0000 (18:42 -0800)
committerYann Collet <cyan@fb.com>
Tue, 24 Dec 2024 02:42:51 +0000 (18:42 -0800)
piggy-backing onto existing compressSequences() fuzzer test

tests/fuzz/Makefile
tests/fuzz/sequence_compression_api.c

index 1333675d01796304189d79b62b219963d4d9645b..a64d2d25289a81c5e098b55ec47d205b98013153 100644 (file)
@@ -28,6 +28,9 @@ LIBZSTD_MK_DIR = ../../lib
 DEBUGLEVEL ?= 2
 ZSTD_LEGACY_SUPPORT ?= 1
 
+.PHONY: default
+default: all
+
 include $(LIBZSTD_MK_DIR)/libzstd.mk
 
 PRGDIR = ../../programs
@@ -101,10 +104,6 @@ FUZZ_RT_OBJ9 := $(FUZZ_RT_OBJ8:.c=.o)
 FUZZ_RT_OBJ10 := $(THIRD_PARTY_SEQ_PROD_OBJ) $(FUZZ_RT_OBJ9)
 FUZZ_ROUND_TRIP_OBJ := $(FUZZ_RT_OBJ10:.S=.o)
 
-.PHONY: default all clean cleanall
-
-default: all
-
 FUZZ_TARGETS :=       \
        simple_round_trip \
        stream_round_trip \
@@ -128,6 +127,7 @@ FUZZ_TARGETS :=       \
        decompress_cross_format \
        generate_sequences
 
+.PHONY: all clean cleanall
 all: libregression.a $(FUZZ_TARGETS)
 
 rt_lib_common_%.o: $(LIB_SRCDIR)/common/%.c
index 5e5e1e60482b8e84d5a61aa030b0c2499c7ec4eb..32710afb936ef18bb5a734852fcc0fe4ff639776 100644 (file)
@@ -155,7 +155,7 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer,
     if (mode == ZSTD_sf_explicitBlockDelimiters) {
         /* ensure that no sequence can be larger than one block */
         literalsSizeLimit = MIN(literalsSizeLimit, blockSizeMax/2);
-        matchLengthMax = MIN(matchLengthMax, blockSizeMax/2);
+        matchLengthMax = MIN(matchLengthMax, (uint32_t)blockSizeMax/2);
     }
 
     while ( nbSeqGenerated < ZSTD_FUZZ_MAX_NBSEQ - 3 /* extra room for explicit delimiters */
@@ -171,7 +171,7 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer,
         if (bytesGenerated > ZSTD_FUZZ_GENERATED_SRC_MAXSIZE) {
             break;
         }
-        offsetBound = (bytesGenerated > windowSize) ? windowSize : bytesGenerated + (uint32_t)dictSize;
+        offsetBound = (bytesGenerated > windowSize) ? (uint32_t)windowSize : bytesGenerated + (uint32_t)dictSize;
         offset = FUZZ_dataProducer_uint32Range(producer, 1, offsetBound);
         if (dictSize > 0 && bytesGenerated <= windowSize) {
             /* Prevent match length from being such that it would be associated with an offset too large
@@ -180,7 +180,7 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer,
              */
             const size_t bytesToReachWindowSize = windowSize - bytesGenerated;
             if (bytesToReachWindowSize < ZSTD_MINMATCH_MIN) {
-                const uint32_t newOffsetBound = offsetBound > windowSize ? windowSize : offsetBound;
+                const uint32_t newOffsetBound = offsetBound > windowSize ? (uint32_t)windowSize : offsetBound;
                 offset = FUZZ_dataProducer_uint32Range(producer, 1, newOffsetBound);
             } else {
                 matchBound = MIN(matchLengthMax, (uint32_t)bytesToReachWindowSize);
@@ -201,14 +201,14 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer,
                 if (blockSize + seqSize > blockSizeMax) {  /* reaching limit : must end block now */
                     const ZSTD_Sequence endBlock = {0, 0, 0, 0};
                     generatedSequences[nbSeqGenerated++] = endBlock;
-                    blockSize = seqSize;
+                    blockSize = (uint32_t)seqSize;
                 }
                 if (split) {
                     const ZSTD_Sequence endBlock = {0, lastLits, 0, 0};
                     generatedSequences[nbSeqGenerated++] = endBlock;
                     assert(lastLits <= seq.litLength);
                     seq.litLength -= lastLits;
-                    blockSize = seqSize - lastLits;
+                    blockSize = (uint32_t)(seqSize - lastLits);
                 } else {
                     blockSize += seqSize;
                 }
@@ -227,10 +227,67 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer,
     return nbSeqGenerated;
 }
 
+static size_t
+transferLiterals(void* dst, size_t dstCapacity, const ZSTD_Sequence* seqs, size_t nbSeqs, const void* src, size_t srcSize)
+{
+    size_t n;
+    char* op = dst;
+    char* const oend = op + dstCapacity;
+    const char* ip = src;
+    const char* const iend = ip + srcSize;
+    for (n=0; n<nbSeqs; n++) {
+        size_t litLen = seqs[n].litLength;
+        size_t mlen = seqs[n].matchLength;
+        assert(op + litLen < oend);
+        assert(ip + litLen + mlen <= iend);
+        memcpy(op, ip, litLen);
+        op += litLen;
+        ip += litLen + mlen;
+    }
+    assert(oend - op >= 8);
+    return (size_t)(op - (char*)dst);
+}
+
+static size_t roundTripTest_compressSequencesAndLiterals(
+                    void* result, size_t resultCapacity,
+                    void* compressed, size_t compressedCapacity,
+                    const void* src, size_t srcSize,
+                    const ZSTD_Sequence* seqs, size_t nbSeqs,
+                    ZSTD_SequenceFormat_e mode)
+{
+    size_t const litCapacity = srcSize + 8;
+    void* literals = malloc(litCapacity);
+    size_t cSize, litSize;
+
+    assert(literals);
+    litSize = transferLiterals(literals, litCapacity, seqs, nbSeqs, src, srcSize);
+
+    cSize = ZSTD_compressSequencesAndLiterals(cctx,
+                                compressed, compressedCapacity,
+                                   seqs, nbSeqs,
+                                   literals, litSize, litCapacity, srcSize);
+    if ( (ZSTD_getErrorCode(cSize) == ZSTD_error_dstSize_tooSmall)
+      && (mode == ZSTD_sf_explicitBlockDelimiters) ) {
+        /* Valid scenario : in explicit delimiter mode,
+         * it might be possible for the compressed size to outgrow dstCapacity.
+         * In which case, it's still a valid fuzzer scenario,
+         * but no roundtrip shall be possible */
+        return 0;
+    }
+    /* round-trip */
+    FUZZ_ZASSERT(cSize);
+    {   size_t const dSize = ZSTD_decompressDCtx(dctx, result, resultCapacity, compressed, cSize);
+        FUZZ_ZASSERT(dSize);
+        FUZZ_ASSERT_MSG(dSize == srcSize, "Incorrect regenerated size");
+        FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, result, srcSize), "Corruption!");
+        return dSize;
+    }
+}
+
 static size_t roundTripTest(void* result, size_t resultCapacity,
                             void* compressed, size_t compressedCapacity,
                             const void* src, size_t srcSize,
-                            const ZSTD_Sequence* seqs, size_t seqSize,
+                            const ZSTD_Sequence* seqs, size_t nbSeqs,
                             unsigned hasDict,
                             ZSTD_SequenceFormat_e mode)
 {
@@ -242,8 +299,16 @@ static size_t roundTripTest(void* result, size_t resultCapacity,
         FUZZ_ZASSERT(ZSTD_DCtx_refDDict(dctx, ddict));
     }
 
+    {   int blockMode;
+        /* compressSequencesAndLiterals() only supports explicitBlockDelimiters */
+        FUZZ_ZASSERT(ZSTD_CCtx_getParameter(cctx, ZSTD_c_blockDelimiters, &blockMode));
+        if (blockMode == ZSTD_sf_explicitBlockDelimiters) {
+            FUZZ_ZASSERT(roundTripTest_compressSequencesAndLiterals(result, resultCapacity, compressed, compressedCapacity, src, srcSize, seqs, nbSeqs, mode));
+        }
+    }
+
     cSize = ZSTD_compressSequences(cctx, compressed, compressedCapacity,
-                                   seqs, seqSize,
+                                   seqs, nbSeqs,
                                    src, srcSize);
     if ( (ZSTD_getErrorCode(cSize) == ZSTD_error_dstSize_tooSmall)
       && (mode == ZSTD_sf_explicitBlockDelimiters) ) {
@@ -298,10 +363,10 @@ int LLVMFuzzerTestOneInput(const uint8_t* src, size_t size)
     ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
     ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 0);
     ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel);
-    ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, wLog);
+    ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, (int)wLog);
     ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, ZSTD_MINMATCH_MIN);
     ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1);
-    ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, mode);
+    ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, (int)mode);
     ZSTD_CCtx_setParameter(cctx, ZSTD_c_forceAttachDict, ZSTD_dictForceAttach);
 
     if (!literalsBuffer) {