]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
[Fuzz] Improve data generation #1723
authorDario Pavlovic <dariop@fb.com>
Tue, 10 Sep 2019 23:14:43 +0000 (16:14 -0700)
committerDario Pavlovic <dariop@fb.com>
Tue, 10 Sep 2019 23:14:43 +0000 (16:14 -0700)
Converting the rest of the tests to use the new data producer.

13 files changed:
tests/fuzz/block_decompress.c
tests/fuzz/block_round_trip.c
tests/fuzz/dictionary_decompress.c
tests/fuzz/dictionary_round_trip.c
tests/fuzz/fuzz_data_producer.c
tests/fuzz/fuzz_data_producer.h
tests/fuzz/simple_compress.c
tests/fuzz/simple_decompress.c
tests/fuzz/simple_round_trip.c
tests/fuzz/stream_decompress.c
tests/fuzz/stream_round_trip.c
tests/fuzz/zstd_helpers.c
tests/fuzz/zstd_helpers.h

index 3cccc32f4e529f165a733ae6e28374a1f6cb69af..a904b44624d9d06e8327ee5480a013a1b8e1ad59 100644 (file)
@@ -28,8 +28,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
     size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX;
 
-    FUZZ_seed(&src, &size);
-
     /* Allocate all buffers and contexts if not already allocated */
     if (neededBufSize > bufSize) {
         free(rBuf);
index 64ca5fc40f9c4712cc975fae36b1ffcee5e1276b..326d5b2474656b6fe2fd6dafc69cdc6a78925cc5 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include "fuzz_helpers.h"
 #include "zstd.h"
+#include "fuzz_data_producer.h"
 
 static const int kMaxClevel = 19;
 
@@ -28,13 +29,12 @@ static ZSTD_DCtx *dctx = NULL;
 static void* cBuf = NULL;
 static void* rBuf = NULL;
 static size_t bufSize = 0;
-static uint32_t seed;
 
 static size_t roundTripTest(void *result, size_t resultCapacity,
                             void *compressed, size_t compressedCapacity,
-                            const void *src, size_t srcSize)
+                            const void *src, size_t srcSize,
+                            int cLevel)
 {
-    int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
     ZSTD_parameters const params = ZSTD_getParams(cLevel, srcSize, 0);
     size_t ret = ZSTD_compressBegin_advanced(cctx, NULL, 0, params, srcSize);
     FUZZ_ZASSERT(ret);
@@ -52,10 +52,11 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
 
 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
-    size_t neededBufSize;
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+    int cLevel = FUZZ_dataProducer_uint32(producer) % kMaxClevel;
+    size = FUZZ_dataProducer_remainingBytes(producer);
 
-    seed = FUZZ_seed(&src, &size);
-    neededBufSize = size;
+    size_t neededBufSize = size;
     if (size > ZSTD_BLOCKSIZE_MAX)
         return 0;
 
@@ -79,11 +80,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 
     {
         size_t const result =
-            roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size);
+            roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size,
+              cLevel);
         FUZZ_ZASSERT(result);
         FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
         FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
     }
+    FUZZ_dataProducer_free(producer);
 #ifndef STATEFUL_FUZZING
     ZSTD_freeCCtx(cctx); cctx = NULL;
     ZSTD_freeDCtx(dctx); dctx = NULL;
index e900054f5a6fd3f939533b1a1705fe7c4b7d6d17..5f660ac52a5cb231e6d673ee25d3574c246ef04a 100644 (file)
 #include <stdio.h>
 #include "fuzz_helpers.h"
 #include "zstd_helpers.h"
+#include "fuzz_data_producer.h"
 
 static ZSTD_DCtx *dctx = NULL;
 
 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
-    uint32_t seed = FUZZ_seed(&src, &size);
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
     FUZZ_dict_t dict;
     ZSTD_DDict* ddict = NULL;
     int i;
@@ -32,19 +33,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
         dctx = ZSTD_createDCtx();
         FUZZ_ASSERT(dctx);
     }
-    dict = FUZZ_train(src, size, &seed);
-    if (FUZZ_rand32(&seed, 0, 1) == 0) {
+    dict = FUZZ_train(src, size, producer);
+    if (FUZZ_dataProducer_uint32Range(producer, 0, 1) == 0) {
         ddict = ZSTD_createDDict(dict.buff, dict.size);
         FUZZ_ASSERT(ddict);
     } else {
         FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
                 dctx, dict.buff, dict.size,
-                (ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1),
-                (ZSTD_dictContentType_e)FUZZ_rand32(&seed, 0, 2)));
+                (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
+                (ZSTD_dictContentType_e)FUZZ_dataProducer_uint32Range(producer, 0, 2)));
     }
     /* Run it 10 times over 10 output sizes. Reuse the context and dict. */
     for (i = 0; i < 10; ++i) {
-        size_t const bufSize = FUZZ_rand32(&seed, 0, 2 * size);
+        size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, 2 * size);
         void* rBuf = malloc(bufSize);
         FUZZ_ASSERT(rBuf);
         if (ddict) {
@@ -55,6 +56,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
         free(rBuf);
     }
     free(dict.buff);
+    FUZZ_dataProducer_free(producer);
     ZSTD_freeDDict(ddict);
 #ifndef STATEFUL_FUZZING
     ZSTD_freeDCtx(dctx); dctx = NULL;
index e28c65c98f06d94d8889bd8e1a4e1ba3c9c97c29..fe0a217b28d3c11fb2f81a919dfef45cb5eb8c45 100644 (file)
 #include <string.h>
 #include "fuzz_helpers.h"
 #include "zstd_helpers.h"
+#include "fuzz_data_producer.h"
 
 static const int kMaxClevel = 19;
 
 static ZSTD_CCtx *cctx = NULL;
 static ZSTD_DCtx *dctx = NULL;
-static uint32_t seed;
 
 static size_t roundTripTest(void *result, size_t resultCapacity,
                             void *compressed, size_t compressedCapacity,
-                            const void *src, size_t srcSize)
+                            const void *src, size_t srcSize,
+                            FUZZ_dataProducer_t *producer)
 {
     ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto;
-    FUZZ_dict_t dict = FUZZ_train(src, srcSize, &seed);
+    FUZZ_dict_t dict = FUZZ_train(src, srcSize, producer);
     size_t cSize;
-    if ((FUZZ_rand(&seed) & 15) == 0) {
-        int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
+    if ((FUZZ_dataProducer_uint32(producer) & 15) == 0) {
+        int const cLevel = FUZZ_dataProducer_uint32(producer) % kMaxClevel;
 
         cSize = ZSTD_compress_usingDict(cctx,
                 compressed, compressedCapacity,
@@ -42,20 +43,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
                 dict.buff, dict.size,
                 cLevel);
     } else {
-        dictContentType = FUZZ_rand32(&seed, 0, 2);
-        FUZZ_setRandomParameters(cctx, srcSize, &seed);
+        dictContentType = FUZZ_dataProducer_uint32Range(producer, 0, 2);
+        FUZZ_setRandomParameters(cctx, srcSize, producer);
         /* Disable checksum so we can use sizes smaller than compress bound. */
         FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0));
         FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
                 cctx, dict.buff, dict.size,
-                (ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1),
+                (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
                 dictContentType));
         cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
     }
     FUZZ_ZASSERT(cSize);
     FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
         dctx, dict.buff, dict.size,
-        (ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1),
+        (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
         dictContentType));
     {
         size_t const ret = ZSTD_decompressDCtx(
@@ -72,12 +73,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     size_t cBufSize = ZSTD_compressBound(size);
     void* cBuf;
 
-    seed = FUZZ_seed(&src, &size);
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+
     /* Half of the time fuzz with a 1 byte smaller output size.
      * This will still succeed because we force the checksum to be disabled,
      * giving us 4 bytes of overhead.
      */
-    cBufSize -= FUZZ_rand32(&seed, 0, 1);
+    cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
     cBuf = malloc(cBufSize);
 
     if (!cctx) {
@@ -91,13 +93,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 
     {
         size_t const result =
-            roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size);
+            roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
         FUZZ_ZASSERT(result);
         FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
         FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
     }
     free(rBuf);
     free(cBuf);
+    FUZZ_dataProducer_free(producer);
 #ifndef STATEFUL_FUZZING
     ZSTD_freeCCtx(cctx); cctx = NULL;
     ZSTD_freeDCtx(dctx); dctx = NULL;
index a083f6362d17ab18bb474cc240ee089e2e7aaec3..6dcc1413da983730408c198185aca2476f3ad3ed 100644 (file)
@@ -49,9 +49,19 @@ uint32_t FUZZ_dataProducer_uint32Range(FUZZ_dataProducer_t *producer, uint32_t m
 }
 
 uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer) {
-  return FUZZ_dataProducer_uint32Range(producer, 0, 0xffffffff);
+    return FUZZ_dataProducer_uint32Range(producer, 0, 0xffffffff);
 }
 
 size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer){
     return producer->size;
 }
+
+size_t FUZZ_dataProducer_contract(FUZZ_dataProducer_t *producer, size_t newSize)
+{
+    newSize = newSize > producer->size ? producer->size : newSize;
+
+    size_t remaining = producer->size - newSize;
+    producer->data = producer->data + remaining;
+    producer->size = newSize;
+    return remaining;
+}
index 4fcf6fd41b936a599b46a29bbb7363d940779741..668c87f29b755513d7e6d3f2d8ec164047e60dab 100644 (file)
@@ -44,4 +44,10 @@ uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer);
 /* Returns the size of the remaining bytes of data in the producer */
 size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer);
 
+/* Tells the producer to contract to newSize bytes of data it currently uses,
+counted from the end, and forget about the rest. If newSize > current data size,
+nothing happens. Returns the number of bytes the producer won't use anymore,
+after contracting. */
+size_t FUZZ_dataProducer_contract(FUZZ_dataProducer_t *producer, size_t newSize);
+
 #endif // FUZZ_DATA_PRODUCER_H
index aaed4035750c3851271ed1421b7666c9b1221a9e..29de4701f34d549084e8f4fd03fde80d6fbf9ff0 100644 (file)
 #include <stdio.h>
 #include "fuzz_helpers.h"
 #include "zstd.h"
+#include "fuzz_data_producer.h"
 
 static ZSTD_CCtx *cctx = NULL;
 
 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
-    uint32_t seed = FUZZ_seed(&src, &size);
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+
+    int const level = (int)FUZZ_dataProducer_uint32Range(
+                                producer, 0, 19 + 3) - 3; /* [-3, 19] */
     size_t const maxSize = ZSTD_compressBound(size);
-    int i;
+    size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, maxSize);
+
+    size = FUZZ_dataProducer_remainingBytes(producer);
+
     if (!cctx) {
         cctx = ZSTD_createCCtx();
         FUZZ_ASSERT(cctx);
     }
-    /* Run it 10 times over 10 output sizes. Reuse the context. */
-    for (i = 0; i < 10; ++i) {
-        int const level = (int)FUZZ_rand32(&seed, 0, 19 + 3) - 3; /* [-3, 19] */
-        size_t const bufSize = FUZZ_rand32(&seed, 0, maxSize);
-        void* rBuf = malloc(bufSize);
-        FUZZ_ASSERT(rBuf);
-        ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, level);
-        free(rBuf);
-    }
 
+    void *rBuf = malloc(bufSize);
+    FUZZ_ASSERT(rBuf);
+    ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, level);
+    free(rBuf);
+    FUZZ_dataProducer_free(producer);
 #ifndef STATEFUL_FUZZING
     ZSTD_freeCCtx(cctx); cctx = NULL;
 #endif
index a68813ee5f48cdcf52108cebd8ddb12cde250019..0ab634fa076a02871378957a18f046dd513f3485 100644 (file)
@@ -25,7 +25,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
   FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
 
-  int i;
   if (!dctx) {
       dctx = ZSTD_createDCtx();
       FUZZ_ASSERT(dctx);
@@ -37,7 +36,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 
   /* Restrict to remaining data. If we run out of data while generating params,
    we should still continue and let decompression happen on empty data. */
-  size = FUZZ_dataProducer_remainingBytes(producer);
+   size = FUZZ_dataProducer_remainingBytes(producer);
 
   ZSTD_decompressDCtx(dctx, rBuf, bufSize, src, size);
   free(rBuf);
index 7e3b6609822fbb3a4edf6f6c6db91b41bac147de..b88d404f975cfcf788e2bd0bd0c87aef63a5198f 100644 (file)
 #include <string.h>
 #include "fuzz_helpers.h"
 #include "zstd_helpers.h"
+#include "fuzz_data_producer.h"
 
 static const int kMaxClevel = 19;
 
 static ZSTD_CCtx *cctx = NULL;
 static ZSTD_DCtx *dctx = NULL;
-static uint32_t seed;
 
 static size_t roundTripTest(void *result, size_t resultCapacity,
                             void *compressed, size_t compressedCapacity,
-                            const void *src, size_t srcSize)
+                            const void *src, size_t srcSize,
+                            FUZZ_dataProducer_t *producer)
 {
     size_t cSize;
-    if (FUZZ_rand(&seed) & 1) {
-        FUZZ_setRandomParameters(cctx, srcSize, &seed);
+    if (FUZZ_dataProducer_uint32(producer) & 1) {
+        FUZZ_setRandomParameters(cctx, srcSize, producer);
         cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
     } else {
-        int const cLevel = FUZZ_rand(&seed) % kMaxClevel;
+        int const cLevel = FUZZ_dataProducer_uint32(producer) % kMaxClevel;
         cSize = ZSTD_compressCCtx(
             cctx, compressed, compressedCapacity, src, srcSize, cLevel);
     }
@@ -51,12 +52,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     size_t cBufSize = ZSTD_compressBound(size);
     void* cBuf;
 
-    seed = FUZZ_seed(&src, &size);
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
     /* Half of the time fuzz with a 1 byte smaller output size.
      * This will still succeed because we don't use a dictionary, so the dictID
      * field is empty, giving us 4 bytes of overhead.
      */
-    cBufSize -= FUZZ_rand32(&seed, 0, 1);
+    cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
     cBuf = malloc(cBufSize);
 
     FUZZ_ASSERT(cBuf && rBuf);
@@ -72,13 +73,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 
     {
         size_t const result =
-            roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size);
+            roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
         FUZZ_ZASSERT(result);
         FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
         FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
     }
     free(rBuf);
     free(cBuf);
+    FUZZ_dataProducer_free(producer);
 #ifndef STATEFUL_FUZZING
     ZSTD_freeCCtx(cctx); cctx = NULL;
     ZSTD_freeDCtx(dctx); dctx = NULL;
index 68e120d7ef6d052209e35ed6f92788dc97441f20..4d5c499660fb11abf896f4c79a747ebe58cdf33a 100644 (file)
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include "fuzz_helpers.h"
 #include "zstd.h"
+#include "fuzz_data_producer.h"
 
 static size_t const kBufSize = ZSTD_BLOCKSIZE_MAX;
 
@@ -26,22 +27,23 @@ static ZSTD_DStream *dstream = NULL;
 static void* buf = NULL;
 uint32_t seed;
 
-static ZSTD_outBuffer makeOutBuffer(void)
+static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer)
 {
   ZSTD_outBuffer buffer = { buf, 0, 0 };
 
-  buffer.size = (FUZZ_rand(&seed) % kBufSize) + 1;
+  buffer.size = (FUZZ_dataProducer_uint32(producer) % kBufSize) + 1;
   FUZZ_ASSERT(buffer.size <= kBufSize);
 
   return buffer;
 }
 
-static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
+static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
+                                  FUZZ_dataProducer_t *producer)
 {
   ZSTD_inBuffer buffer = { *src, 0, 0 };
 
   FUZZ_ASSERT(*size > 0);
-  buffer.size = (FUZZ_rand(&seed) % *size) + 1;
+  buffer.size = (FUZZ_dataProducer_uint32(producer) % *size) + 1;
   FUZZ_ASSERT(buffer.size <= *size);
   *src += buffer.size;
   *size -= buffer.size;
@@ -51,13 +53,17 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
 
 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
-    seed = FUZZ_seed(&src, &size);
+    /* Give a random portion of src data to the producer, to use for
+    parameter generation. The rest will be used for (de)compression */
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+    size_t producerSliceSize = FUZZ_dataProducer_uint32Range(producer, 0, size);
+    size = FUZZ_dataProducer_contract(producer, producerSliceSize);
 
     /* Allocate all buffers and contexts if not already allocated */
     if (!buf) {
       buf = malloc(kBufSize);
-      FUZZ_ASSERT(buf);
-    }
+        FUZZ_ASSERT(buf);
+      }
 
     if (!dstream) {
         dstream = ZSTD_createDStream();
@@ -67,9 +73,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     }
 
     while (size > 0) {
-        ZSTD_inBuffer in = makeInBuffer(&src, &size);
+        ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
         while (in.pos != in.size) {
-            ZSTD_outBuffer out = makeOutBuffer();
+            ZSTD_outBuffer out = makeOutBuffer(producer);
             size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
             if (ZSTD_isError(rc)) goto error;
         }
@@ -79,5 +85,6 @@ error:
 #ifndef STATEFUL_FUZZING
     ZSTD_freeDStream(dstream); dstream = NULL;
 #endif
+    FUZZ_dataProducer_free(producer);
     return 0;
 }
index d13c2dbe7e006b668a437548479cc783217e1e62..4569222f1985a4f0c73652a95d016252312f641b 100644 (file)
 #include <string.h>
 #include "fuzz_helpers.h"
 #include "zstd_helpers.h"
+#include "fuzz_data_producer.h"
 
 ZSTD_CCtx *cctx = NULL;
 static ZSTD_DCtx *dctx = NULL;
 static uint8_t* cBuf = NULL;
 static uint8_t* rBuf = NULL;
 static size_t bufSize = 0;
-static uint32_t seed;
 
-static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity)
+static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity,
+                                    FUZZ_dataProducer_t *producer)
 {
     ZSTD_outBuffer buffer = { dst, 0, 0 };
 
     FUZZ_ASSERT(capacity > 0);
-    buffer.size = (FUZZ_rand(&seed) % capacity) + 1;
+    buffer.size = (FUZZ_dataProducer_uint32(producer) % capacity) + 1;
     FUZZ_ASSERT(buffer.size <= capacity);
 
     return buffer;
 }
 
-static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
+static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
+                                  FUZZ_dataProducer_t *producer)
 {
     ZSTD_inBuffer buffer = { *src, 0, 0 };
 
     FUZZ_ASSERT(*size > 0);
-    buffer.size = (FUZZ_rand(&seed) % *size) + 1;
+    buffer.size = (FUZZ_dataProducer_uint32(producer) % *size) + 1;
     FUZZ_ASSERT(buffer.size <= *size);
     *src += buffer.size;
     *size -= buffer.size;
@@ -53,23 +55,24 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
 }
 
 static size_t compress(uint8_t *dst, size_t capacity,
-                       const uint8_t *src, size_t srcSize)
+                       const uint8_t *src, size_t srcSize,
+                     FUZZ_dataProducer_t *producer)
 {
     size_t dstSize = 0;
     ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
-    FUZZ_setRandomParameters(cctx, srcSize, &seed);
+    FUZZ_setRandomParameters(cctx, srcSize, producer);
 
     while (srcSize > 0) {
-        ZSTD_inBuffer in = makeInBuffer(&src, &srcSize);
+        ZSTD_inBuffer in = makeInBuffer(&src, &srcSize, producer);
         /* Mode controls the action. If mode == -1 we pick a new mode */
         int mode = -1;
         while (in.pos < in.size || mode != -1) {
-            ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
+            ZSTD_outBuffer out = makeOutBuffer(dst, capacity, producer);
             /* Previous action finished, pick a new mode. */
-            if (mode == -1) mode = FUZZ_rand(&seed) % 10;
+            if (mode == -1) mode = FUZZ_dataProducer_uint32(producer) % 10;
             switch (mode) {
-                case 0: /* fall-though */
-                case 1: /* fall-though */
+                case 0: /* fall-through */
+                case 1: /* fall-through */
                 case 2: {
                     size_t const ret =
                         ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush);
@@ -85,9 +88,9 @@ static size_t compress(uint8_t *dst, size_t capacity,
                     /* Reset the compressor when the frame is finished */
                     if (ret == 0) {
                         ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
-                        if ((FUZZ_rand(&seed) & 7) == 0) {
+                        if ((FUZZ_dataProducer_uint32(producer) & 7) == 0) {
                             size_t const remaining = in.size - in.pos;
-                            FUZZ_setRandomParameters(cctx, remaining, &seed);
+                            FUZZ_setRandomParameters(cctx, remaining, producer);
                         }
                         mode = -1;
                     }
@@ -107,7 +110,7 @@ static size_t compress(uint8_t *dst, size_t capacity,
     }
     for (;;) {
         ZSTD_inBuffer in = {NULL, 0, 0};
-        ZSTD_outBuffer out = makeOutBuffer(dst, capacity);
+        ZSTD_outBuffer out = makeOutBuffer(dst, capacity, producer);
         size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
         FUZZ_ZASSERT(ret);
 
@@ -123,9 +126,13 @@ static size_t compress(uint8_t *dst, size_t capacity,
 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
 {
     size_t neededBufSize;
+    neededBufSize = ZSTD_compressBound(size) * 5;
 
-    seed = FUZZ_seed(&src, &size);
-    neededBufSize = ZSTD_compressBound(size) * 2;
+    /* Give a random portion of src data to the producer, to use for
+    parameter generation. The rest will be used for (de)compression */
+    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+    size_t producerSliceSize = FUZZ_dataProducer_uint32Range(producer, 0, size);
+    size = FUZZ_dataProducer_contract(producer, producerSliceSize);
 
     /* Allocate all buffers and contexts if not already allocated */
     if (neededBufSize > bufSize) {
@@ -146,7 +153,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     }
 
     {
-        size_t const cSize = compress(cBuf, neededBufSize, src, size);
+        size_t const cSize = compress(cBuf, neededBufSize, src, size, producer);
         size_t const rSize =
             ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize);
         FUZZ_ZASSERT(rSize);
@@ -154,6 +161,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
         FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
     }
 
+    FUZZ_dataProducer_free(producer);
 #ifndef STATEFUL_FUZZING
     ZSTD_freeCCtx(cctx); cctx = NULL;
     ZSTD_freeDCtx(dctx); dctx = NULL;
index 5ff057b8cdc25b984bb5a91c86ff2baa404a954b..2635de4ccbe404fa79685e4beabe08ef08d5ec5a 100644 (file)
@@ -23,47 +23,47 @@ static void set(ZSTD_CCtx *cctx, ZSTD_cParameter param, int value)
 }
 
 static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min,
-                    unsigned max, uint32_t *state) {
-    unsigned const value = FUZZ_rand32(state, min, max);
+                    unsigned max, FUZZ_dataProducer_t *producer) {
+    unsigned const value = FUZZ_dataProducer_uint32Range(producer, min, max);
     set(cctx, param, value);
 }
 
-ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state)
+ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, FUZZ_dataProducer_t *producer)
 {
     /* Select compression parameters */
     ZSTD_compressionParameters cParams;
-    cParams.windowLog = FUZZ_rand32(state, ZSTD_WINDOWLOG_MIN, 15);
-    cParams.hashLog = FUZZ_rand32(state, ZSTD_HASHLOG_MIN, 15);
-    cParams.chainLog = FUZZ_rand32(state, ZSTD_CHAINLOG_MIN, 16);
-    cParams.searchLog = FUZZ_rand32(state, ZSTD_SEARCHLOG_MIN, 9);
-    cParams.minMatch = FUZZ_rand32(state, ZSTD_MINMATCH_MIN,
+    cParams.windowLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, 15);
+    cParams.hashLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_HASHLOG_MIN, 15);
+    cParams.chainLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_CHAINLOG_MIN, 16);
+    cParams.searchLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_SEARCHLOG_MIN, 9);
+    cParams.minMatch = FUZZ_dataProducer_uint32Range(producer, ZSTD_MINMATCH_MIN,
                                           ZSTD_MINMATCH_MAX);
-    cParams.targetLength = FUZZ_rand32(state, 0, 512);
-    cParams.strategy = FUZZ_rand32(state, ZSTD_STRATEGY_MIN, ZSTD_STRATEGY_MAX);
+    cParams.targetLength = FUZZ_dataProducer_uint32Range(producer, 0, 512);
+    cParams.strategy = FUZZ_dataProducer_uint32Range(producer, ZSTD_STRATEGY_MIN, ZSTD_STRATEGY_MAX);
     return ZSTD_adjustCParams(cParams, srcSize, 0);
 }
 
-ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state)
+ZSTD_frameParameters FUZZ_randomFParams(FUZZ_dataProducer_t *producer)
 {
     /* Select frame parameters */
     ZSTD_frameParameters fParams;
-    fParams.contentSizeFlag = FUZZ_rand32(state, 0, 1);
-    fParams.checksumFlag = FUZZ_rand32(state, 0, 1);
-    fParams.noDictIDFlag = FUZZ_rand32(state, 0, 1);
+    fParams.contentSizeFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
+    fParams.checksumFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
+    fParams.noDictIDFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
     return fParams;
 }
 
-ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state)
+ZSTD_parameters FUZZ_randomParams(size_t srcSize, FUZZ_dataProducer_t *producer)
 {
     ZSTD_parameters params;
-    params.cParams = FUZZ_randomCParams(srcSize, state);
-    params.fParams = FUZZ_randomFParams(state);
+    params.cParams = FUZZ_randomCParams(srcSize, producer);
+    params.fParams = FUZZ_randomFParams(producer);
     return params;
 }
 
-void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state)
+void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, FUZZ_dataProducer_t *producer)
 {
-    ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, state);
+    ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, producer);
     set(cctx, ZSTD_c_windowLog, cParams.windowLog);
     set(cctx, ZSTD_c_hashLog, cParams.hashLog);
     set(cctx, ZSTD_c_chainLog, cParams.chainLog);
@@ -72,30 +72,30 @@ void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state)
     set(cctx, ZSTD_c_targetLength, cParams.targetLength);
     set(cctx, ZSTD_c_strategy, cParams.strategy);
     /* Select frame parameters */
-    setRand(cctx, ZSTD_c_contentSizeFlag, 0, 1, state);
-    setRand(cctx, ZSTD_c_checksumFlag, 0, 1, state);
-    setRand(cctx, ZSTD_c_dictIDFlag, 0, 1, state);
+    setRand(cctx, ZSTD_c_contentSizeFlag, 0, 1, producer);
+    setRand(cctx, ZSTD_c_checksumFlag, 0, 1, producer);
+    setRand(cctx, ZSTD_c_dictIDFlag, 0, 1, producer);
     /* Select long distance matching parameters */
-    setRand(cctx, ZSTD_c_enableLongDistanceMatching, 0, 1, state);
-    setRand(cctx, ZSTD_c_ldmHashLog, ZSTD_HASHLOG_MIN, 16, state);
+    setRand(cctx, ZSTD_c_enableLongDistanceMatching, 0, 1, producer);
+    setRand(cctx, ZSTD_c_ldmHashLog, ZSTD_HASHLOG_MIN, 16, producer);
     setRand(cctx, ZSTD_c_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN,
-            ZSTD_LDM_MINMATCH_MAX, state);
+            ZSTD_LDM_MINMATCH_MAX, producer);
     setRand(cctx, ZSTD_c_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX,
-            state);
+            producer);
     setRand(cctx, ZSTD_c_ldmHashRateLog, ZSTD_LDM_HASHRATELOG_MIN,
-            ZSTD_LDM_HASHRATELOG_MAX, state);
+            ZSTD_LDM_HASHRATELOG_MAX, producer);
     /* Set misc parameters */
-    setRand(cctx, ZSTD_c_nbWorkers, 0, 2, state);
-    setRand(cctx, ZSTD_c_rsyncable, 0, 1, state);
-    setRand(cctx, ZSTD_c_forceMaxWindow, 0, 1, state);
-    setRand(cctx, ZSTD_c_literalCompressionMode, 0, 2, state);
-    setRand(cctx, ZSTD_c_forceAttachDict, 0, 2, state);
-    if (FUZZ_rand32(state, 0, 1) == 0) {
-      setRand(cctx, ZSTD_c_srcSizeHint, ZSTD_SRCSIZEHINT_MIN, 2 * srcSize, state);
+    setRand(cctx, ZSTD_c_nbWorkers, 0, 2, producer);
+    setRand(cctx, ZSTD_c_rsyncable, 0, 1, producer);
+    setRand(cctx, ZSTD_c_forceMaxWindow, 0, 1, producer);
+    setRand(cctx, ZSTD_c_literalCompressionMode, 0, 2, producer);
+    setRand(cctx, ZSTD_c_forceAttachDict, 0, 2, producer);
+    if (FUZZ_dataProducer_uint32Range(producer, 0, 1) == 0) {
+      setRand(cctx, ZSTD_c_srcSizeHint, ZSTD_SRCSIZEHINT_MIN, 2 * srcSize, producer);
     }
 }
 
-FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, uint32_t *state)
+FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, FUZZ_dataProducer_t *producer)
 {
     size_t const dictSize = MAX(srcSize / 8, 1024);
     size_t const totalSampleSize = dictSize * 11;
@@ -110,7 +110,7 @@ FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, uint32_t *state)
 
     for (sample = 0; sample < nbSamples; ++sample) {
       size_t const remaining = totalSampleSize - pos;
-      size_t const offset = FUZZ_rand32(state, 0, MAX(srcSize, 1) - 1);
+      size_t const offset = FUZZ_dataProducer_uint32Range(producer, 0, MAX(srcSize, 1) - 1);
       size_t const limit = MIN(srcSize - offset, remaining);
       size_t const toCopy = MIN(limit, remaining / (nbSamples - sample));
       memcpy(samples + pos, src + offset, toCopy);
index 457e6e995f0d0a7c8c227ad2826f46eeb632b2e2..f2001f8b27824d0fa56978f416b4891afe7eeb16 100644 (file)
 #define ZSTD_STATIC_LINKING_ONLY
 
 #include "zstd.h"
+#include "fuzz_data_producer.h"
 #include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, uint32_t *state);
+void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, FUZZ_dataProducer_t *producer);
 
-ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, uint32_t *state);
-ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state);
-ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state);
+ZSTD_compressionParameters FUZZ_randomCParams(size_t srcSize, FUZZ_dataProducer_t *producer);
+ZSTD_frameParameters FUZZ_randomFParams(FUZZ_dataProducer_t *producer);
+ZSTD_parameters FUZZ_randomParams(size_t srcSize, FUZZ_dataProducer_t *producer);
 
 typedef struct {
   void* buff;
@@ -38,7 +39,7 @@ typedef struct {
  * NOTE: Don't use this to train production dictionaries, it is only optimized
  * for speed, and doesn't care about dictionary quality.
  */
-FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, uint32_t *state);
+FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, FUZZ_dataProducer_t *producer);
 
 
 #ifdef __cplusplus