1
0
mirror of https://github.com/facebook/zstd.git synced 2025-08-05 19:15:58 +03:00

[Fuzz] Improve data generation #1723

Converting the rest of the tests to use the new data producer.
This commit is contained in:
Dario Pavlovic
2019-09-10 16:14:43 -07:00
parent ea1ad123da
commit 0630d084cb
13 changed files with 159 additions and 117 deletions

View File

@@ -28,8 +28,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
{ {
size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX; size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX;
FUZZ_seed(&src, &size);
/* Allocate all buffers and contexts if not already allocated */ /* Allocate all buffers and contexts if not already allocated */
if (neededBufSize > bufSize) { if (neededBufSize > bufSize) {
free(rBuf); free(rBuf);

View File

@@ -20,6 +20,7 @@
#include <string.h> #include <string.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd.h" #include "zstd.h"
#include "fuzz_data_producer.h"
static const int kMaxClevel = 19; static const int kMaxClevel = 19;
@@ -28,13 +29,12 @@ static ZSTD_DCtx *dctx = NULL;
static void* cBuf = NULL; static void* cBuf = NULL;
static void* rBuf = NULL; static void* rBuf = NULL;
static size_t bufSize = 0; static size_t bufSize = 0;
static uint32_t seed;
static size_t roundTripTest(void *result, size_t resultCapacity, static size_t roundTripTest(void *result, size_t resultCapacity,
void *compressed, size_t compressedCapacity, 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); ZSTD_parameters const params = ZSTD_getParams(cLevel, srcSize, 0);
size_t ret = ZSTD_compressBegin_advanced(cctx, NULL, 0, params, srcSize); size_t ret = ZSTD_compressBegin_advanced(cctx, NULL, 0, params, srcSize);
FUZZ_ZASSERT(ret); 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) 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); size_t neededBufSize = size;
neededBufSize = size;
if (size > ZSTD_BLOCKSIZE_MAX) if (size > ZSTD_BLOCKSIZE_MAX)
return 0; return 0;
@@ -79,11 +80,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
{ {
size_t const result = size_t const result =
roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size); roundTripTest(rBuf, neededBufSize, cBuf, neededBufSize, src, size,
cLevel);
FUZZ_ZASSERT(result); FUZZ_ZASSERT(result);
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
} }
FUZZ_dataProducer_free(producer);
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeCCtx(cctx); cctx = NULL;
ZSTD_freeDCtx(dctx); dctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL;

View File

@@ -18,12 +18,13 @@
#include <stdio.h> #include <stdio.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd_helpers.h" #include "zstd_helpers.h"
#include "fuzz_data_producer.h"
static ZSTD_DCtx *dctx = NULL; static ZSTD_DCtx *dctx = NULL;
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) 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; FUZZ_dict_t dict;
ZSTD_DDict* ddict = NULL; ZSTD_DDict* ddict = NULL;
int i; int i;
@@ -32,19 +33,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
dctx = ZSTD_createDCtx(); dctx = ZSTD_createDCtx();
FUZZ_ASSERT(dctx); FUZZ_ASSERT(dctx);
} }
dict = FUZZ_train(src, size, &seed); dict = FUZZ_train(src, size, producer);
if (FUZZ_rand32(&seed, 0, 1) == 0) { if (FUZZ_dataProducer_uint32Range(producer, 0, 1) == 0) {
ddict = ZSTD_createDDict(dict.buff, dict.size); ddict = ZSTD_createDDict(dict.buff, dict.size);
FUZZ_ASSERT(ddict); FUZZ_ASSERT(ddict);
} else { } else {
FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced( FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
dctx, dict.buff, dict.size, dctx, dict.buff, dict.size,
(ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1), (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
(ZSTD_dictContentType_e)FUZZ_rand32(&seed, 0, 2))); (ZSTD_dictContentType_e)FUZZ_dataProducer_uint32Range(producer, 0, 2)));
} }
/* Run it 10 times over 10 output sizes. Reuse the context and dict. */ /* Run it 10 times over 10 output sizes. Reuse the context and dict. */
for (i = 0; i < 10; ++i) { 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); void* rBuf = malloc(bufSize);
FUZZ_ASSERT(rBuf); FUZZ_ASSERT(rBuf);
if (ddict) { if (ddict) {
@@ -55,6 +56,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
free(rBuf); free(rBuf);
} }
free(dict.buff); free(dict.buff);
FUZZ_dataProducer_free(producer);
ZSTD_freeDDict(ddict); ZSTD_freeDDict(ddict);
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeDCtx(dctx); dctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL;

View File

@@ -19,22 +19,23 @@
#include <string.h> #include <string.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd_helpers.h" #include "zstd_helpers.h"
#include "fuzz_data_producer.h"
static const int kMaxClevel = 19; static const int kMaxClevel = 19;
static ZSTD_CCtx *cctx = NULL; static ZSTD_CCtx *cctx = NULL;
static ZSTD_DCtx *dctx = NULL; static ZSTD_DCtx *dctx = NULL;
static uint32_t seed;
static size_t roundTripTest(void *result, size_t resultCapacity, static size_t roundTripTest(void *result, size_t resultCapacity,
void *compressed, size_t compressedCapacity, 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; 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; size_t cSize;
if ((FUZZ_rand(&seed) & 15) == 0) { if ((FUZZ_dataProducer_uint32(producer) & 15) == 0) {
int const cLevel = FUZZ_rand(&seed) % kMaxClevel; int const cLevel = FUZZ_dataProducer_uint32(producer) % kMaxClevel;
cSize = ZSTD_compress_usingDict(cctx, cSize = ZSTD_compress_usingDict(cctx,
compressed, compressedCapacity, compressed, compressedCapacity,
@@ -42,20 +43,20 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
dict.buff, dict.size, dict.buff, dict.size,
cLevel); cLevel);
} else { } else {
dictContentType = FUZZ_rand32(&seed, 0, 2); dictContentType = FUZZ_dataProducer_uint32Range(producer, 0, 2);
FUZZ_setRandomParameters(cctx, srcSize, &seed); FUZZ_setRandomParameters(cctx, srcSize, producer);
/* Disable checksum so we can use sizes smaller than compress bound. */ /* 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_setParameter(cctx, ZSTD_c_checksumFlag, 0));
FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced( FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
cctx, dict.buff, dict.size, cctx, dict.buff, dict.size,
(ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1), (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
dictContentType)); dictContentType));
cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize); cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
} }
FUZZ_ZASSERT(cSize); FUZZ_ZASSERT(cSize);
FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced( FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
dctx, dict.buff, dict.size, dctx, dict.buff, dict.size,
(ZSTD_dictLoadMethod_e)FUZZ_rand32(&seed, 0, 1), (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
dictContentType)); dictContentType));
{ {
size_t const ret = ZSTD_decompressDCtx( 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); size_t cBufSize = ZSTD_compressBound(size);
void* cBuf; 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. /* Half of the time fuzz with a 1 byte smaller output size.
* This will still succeed because we force the checksum to be disabled, * This will still succeed because we force the checksum to be disabled,
* giving us 4 bytes of overhead. * giving us 4 bytes of overhead.
*/ */
cBufSize -= FUZZ_rand32(&seed, 0, 1); cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
cBuf = malloc(cBufSize); cBuf = malloc(cBufSize);
if (!cctx) { if (!cctx) {
@@ -91,13 +93,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
{ {
size_t const result = size_t const result =
roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size); roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
FUZZ_ZASSERT(result); FUZZ_ZASSERT(result);
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
} }
free(rBuf); free(rBuf);
free(cBuf); free(cBuf);
FUZZ_dataProducer_free(producer);
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeCCtx(cctx); cctx = NULL;
ZSTD_freeDCtx(dctx); dctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL;

View File

@@ -55,3 +55,13 @@ uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer) {
size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer){ size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer){
return producer->size; 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;
}

View 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 */ /* Returns the size of the remaining bytes of data in the producer */
size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *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 #endif // FUZZ_DATA_PRODUCER_H

View File

@@ -18,28 +18,31 @@
#include <stdio.h> #include <stdio.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd.h" #include "zstd.h"
#include "fuzz_data_producer.h"
static ZSTD_CCtx *cctx = NULL; static ZSTD_CCtx *cctx = NULL;
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) 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); 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) { if (!cctx) {
cctx = ZSTD_createCCtx(); cctx = ZSTD_createCCtx();
FUZZ_ASSERT(cctx); 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); void *rBuf = malloc(bufSize);
FUZZ_ASSERT(rBuf); FUZZ_ASSERT(rBuf);
ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, level); ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, level);
free(rBuf); free(rBuf);
} FUZZ_dataProducer_free(producer);
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeCCtx(cctx); cctx = NULL;
#endif #endif

View File

@@ -25,7 +25,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
{ {
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
int i;
if (!dctx) { if (!dctx) {
dctx = ZSTD_createDCtx(); dctx = ZSTD_createDCtx();
FUZZ_ASSERT(dctx); FUZZ_ASSERT(dctx);

View File

@@ -20,23 +20,24 @@
#include <string.h> #include <string.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd_helpers.h" #include "zstd_helpers.h"
#include "fuzz_data_producer.h"
static const int kMaxClevel = 19; static const int kMaxClevel = 19;
static ZSTD_CCtx *cctx = NULL; static ZSTD_CCtx *cctx = NULL;
static ZSTD_DCtx *dctx = NULL; static ZSTD_DCtx *dctx = NULL;
static uint32_t seed;
static size_t roundTripTest(void *result, size_t resultCapacity, static size_t roundTripTest(void *result, size_t resultCapacity,
void *compressed, size_t compressedCapacity, void *compressed, size_t compressedCapacity,
const void *src, size_t srcSize) const void *src, size_t srcSize,
FUZZ_dataProducer_t *producer)
{ {
size_t cSize; size_t cSize;
if (FUZZ_rand(&seed) & 1) { if (FUZZ_dataProducer_uint32(producer) & 1) {
FUZZ_setRandomParameters(cctx, srcSize, &seed); FUZZ_setRandomParameters(cctx, srcSize, producer);
cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize); cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
} else { } else {
int const cLevel = FUZZ_rand(&seed) % kMaxClevel; int const cLevel = FUZZ_dataProducer_uint32(producer) % kMaxClevel;
cSize = ZSTD_compressCCtx( cSize = ZSTD_compressCCtx(
cctx, compressed, compressedCapacity, src, srcSize, cLevel); 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); size_t cBufSize = ZSTD_compressBound(size);
void* cBuf; 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. /* 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 * This will still succeed because we don't use a dictionary, so the dictID
* field is empty, giving us 4 bytes of overhead. * 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); cBuf = malloc(cBufSize);
FUZZ_ASSERT(cBuf && rBuf); FUZZ_ASSERT(cBuf && rBuf);
@@ -72,13 +73,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
{ {
size_t const result = size_t const result =
roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size); roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
FUZZ_ZASSERT(result); FUZZ_ZASSERT(result);
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size"); FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!"); FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
} }
free(rBuf); free(rBuf);
free(cBuf); free(cBuf);
FUZZ_dataProducer_free(producer);
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeCCtx(cctx); cctx = NULL;
ZSTD_freeDCtx(dctx); dctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL;

View File

@@ -19,6 +19,7 @@
#include <stdio.h> #include <stdio.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd.h" #include "zstd.h"
#include "fuzz_data_producer.h"
static size_t const kBufSize = ZSTD_BLOCKSIZE_MAX; static size_t const kBufSize = ZSTD_BLOCKSIZE_MAX;
@@ -26,22 +27,23 @@ static ZSTD_DStream *dstream = NULL;
static void* buf = NULL; static void* buf = NULL;
uint32_t seed; uint32_t seed;
static ZSTD_outBuffer makeOutBuffer(void) static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer)
{ {
ZSTD_outBuffer buffer = { buf, 0, 0 }; 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); FUZZ_ASSERT(buffer.size <= kBufSize);
return buffer; 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 }; ZSTD_inBuffer buffer = { *src, 0, 0 };
FUZZ_ASSERT(*size > 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); FUZZ_ASSERT(buffer.size <= *size);
*src += buffer.size; *src += buffer.size;
*size -= buffer.size; *size -= buffer.size;
@@ -51,7 +53,11 @@ static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size)
int LLVMFuzzerTestOneInput(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 */ /* Allocate all buffers and contexts if not already allocated */
if (!buf) { if (!buf) {
@@ -67,9 +73,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
} }
while (size > 0) { while (size > 0) {
ZSTD_inBuffer in = makeInBuffer(&src, &size); ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
while (in.pos != in.size) { while (in.pos != in.size) {
ZSTD_outBuffer out = makeOutBuffer(); ZSTD_outBuffer out = makeOutBuffer(producer);
size_t const rc = ZSTD_decompressStream(dstream, &out, &in); size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
if (ZSTD_isError(rc)) goto error; if (ZSTD_isError(rc)) goto error;
} }
@@ -79,5 +85,6 @@ error:
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeDStream(dstream); dstream = NULL; ZSTD_freeDStream(dstream); dstream = NULL;
#endif #endif
FUZZ_dataProducer_free(producer);
return 0; return 0;
} }

View File

@@ -20,31 +20,33 @@
#include <string.h> #include <string.h>
#include "fuzz_helpers.h" #include "fuzz_helpers.h"
#include "zstd_helpers.h" #include "zstd_helpers.h"
#include "fuzz_data_producer.h"
ZSTD_CCtx *cctx = NULL; ZSTD_CCtx *cctx = NULL;
static ZSTD_DCtx *dctx = NULL; static ZSTD_DCtx *dctx = NULL;
static uint8_t* cBuf = NULL; static uint8_t* cBuf = NULL;
static uint8_t* rBuf = NULL; static uint8_t* rBuf = NULL;
static size_t bufSize = 0; 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 }; ZSTD_outBuffer buffer = { dst, 0, 0 };
FUZZ_ASSERT(capacity > 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); FUZZ_ASSERT(buffer.size <= capacity);
return buffer; 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 }; ZSTD_inBuffer buffer = { *src, 0, 0 };
FUZZ_ASSERT(*size > 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); FUZZ_ASSERT(buffer.size <= *size);
*src += buffer.size; *src += buffer.size;
*size -= 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, 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; size_t dstSize = 0;
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
FUZZ_setRandomParameters(cctx, srcSize, &seed); FUZZ_setRandomParameters(cctx, srcSize, producer);
while (srcSize > 0) { 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 */ /* Mode controls the action. If mode == -1 we pick a new mode */
int mode = -1; int mode = -1;
while (in.pos < in.size || 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. */ /* 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) { switch (mode) {
case 0: /* fall-though */ case 0: /* fall-through */
case 1: /* fall-though */ case 1: /* fall-through */
case 2: { case 2: {
size_t const ret = size_t const ret =
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush); 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 */ /* Reset the compressor when the frame is finished */
if (ret == 0) { if (ret == 0) {
ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 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; size_t const remaining = in.size - in.pos;
FUZZ_setRandomParameters(cctx, remaining, &seed); FUZZ_setRandomParameters(cctx, remaining, producer);
} }
mode = -1; mode = -1;
} }
@@ -107,7 +110,7 @@ static size_t compress(uint8_t *dst, size_t capacity,
} }
for (;;) { for (;;) {
ZSTD_inBuffer in = {NULL, 0, 0}; 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); size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
FUZZ_ZASSERT(ret); 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) int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
{ {
size_t neededBufSize; size_t neededBufSize;
neededBufSize = ZSTD_compressBound(size) * 5;
seed = FUZZ_seed(&src, &size); /* Give a random portion of src data to the producer, to use for
neededBufSize = ZSTD_compressBound(size) * 2; 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 */ /* Allocate all buffers and contexts if not already allocated */
if (neededBufSize > bufSize) { 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 = size_t const rSize =
ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize); ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize);
FUZZ_ZASSERT(rSize); 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_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
} }
FUZZ_dataProducer_free(producer);
#ifndef STATEFUL_FUZZING #ifndef STATEFUL_FUZZING
ZSTD_freeCCtx(cctx); cctx = NULL; ZSTD_freeCCtx(cctx); cctx = NULL;
ZSTD_freeDCtx(dctx); dctx = NULL; ZSTD_freeDCtx(dctx); dctx = NULL;

View 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, static void setRand(ZSTD_CCtx *cctx, ZSTD_cParameter param, unsigned min,
unsigned max, uint32_t *state) { unsigned max, FUZZ_dataProducer_t *producer) {
unsigned const value = FUZZ_rand32(state, min, max); unsigned const value = FUZZ_dataProducer_uint32Range(producer, min, max);
set(cctx, param, value); 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 */ /* Select compression parameters */
ZSTD_compressionParameters cParams; ZSTD_compressionParameters cParams;
cParams.windowLog = FUZZ_rand32(state, ZSTD_WINDOWLOG_MIN, 15); cParams.windowLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, 15);
cParams.hashLog = FUZZ_rand32(state, ZSTD_HASHLOG_MIN, 15); cParams.hashLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_HASHLOG_MIN, 15);
cParams.chainLog = FUZZ_rand32(state, ZSTD_CHAINLOG_MIN, 16); cParams.chainLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_CHAINLOG_MIN, 16);
cParams.searchLog = FUZZ_rand32(state, ZSTD_SEARCHLOG_MIN, 9); cParams.searchLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_SEARCHLOG_MIN, 9);
cParams.minMatch = FUZZ_rand32(state, ZSTD_MINMATCH_MIN, cParams.minMatch = FUZZ_dataProducer_uint32Range(producer, ZSTD_MINMATCH_MIN,
ZSTD_MINMATCH_MAX); ZSTD_MINMATCH_MAX);
cParams.targetLength = FUZZ_rand32(state, 0, 512); cParams.targetLength = FUZZ_dataProducer_uint32Range(producer, 0, 512);
cParams.strategy = FUZZ_rand32(state, ZSTD_STRATEGY_MIN, ZSTD_STRATEGY_MAX); cParams.strategy = FUZZ_dataProducer_uint32Range(producer, ZSTD_STRATEGY_MIN, ZSTD_STRATEGY_MAX);
return ZSTD_adjustCParams(cParams, srcSize, 0); return ZSTD_adjustCParams(cParams, srcSize, 0);
} }
ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state) ZSTD_frameParameters FUZZ_randomFParams(FUZZ_dataProducer_t *producer)
{ {
/* Select frame parameters */ /* Select frame parameters */
ZSTD_frameParameters fParams; ZSTD_frameParameters fParams;
fParams.contentSizeFlag = FUZZ_rand32(state, 0, 1); fParams.contentSizeFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
fParams.checksumFlag = FUZZ_rand32(state, 0, 1); fParams.checksumFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
fParams.noDictIDFlag = FUZZ_rand32(state, 0, 1); fParams.noDictIDFlag = FUZZ_dataProducer_uint32Range(producer, 0, 1);
return fParams; 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; ZSTD_parameters params;
params.cParams = FUZZ_randomCParams(srcSize, state); params.cParams = FUZZ_randomCParams(srcSize, producer);
params.fParams = FUZZ_randomFParams(state); params.fParams = FUZZ_randomFParams(producer);
return params; 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_windowLog, cParams.windowLog);
set(cctx, ZSTD_c_hashLog, cParams.hashLog); set(cctx, ZSTD_c_hashLog, cParams.hashLog);
set(cctx, ZSTD_c_chainLog, cParams.chainLog); 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_targetLength, cParams.targetLength);
set(cctx, ZSTD_c_strategy, cParams.strategy); set(cctx, ZSTD_c_strategy, cParams.strategy);
/* Select frame parameters */ /* Select frame parameters */
setRand(cctx, ZSTD_c_contentSizeFlag, 0, 1, state); setRand(cctx, ZSTD_c_contentSizeFlag, 0, 1, producer);
setRand(cctx, ZSTD_c_checksumFlag, 0, 1, state); setRand(cctx, ZSTD_c_checksumFlag, 0, 1, producer);
setRand(cctx, ZSTD_c_dictIDFlag, 0, 1, state); setRand(cctx, ZSTD_c_dictIDFlag, 0, 1, producer);
/* Select long distance matching parameters */ /* Select long distance matching parameters */
setRand(cctx, ZSTD_c_enableLongDistanceMatching, 0, 1, state); setRand(cctx, ZSTD_c_enableLongDistanceMatching, 0, 1, producer);
setRand(cctx, ZSTD_c_ldmHashLog, ZSTD_HASHLOG_MIN, 16, state); setRand(cctx, ZSTD_c_ldmHashLog, ZSTD_HASHLOG_MIN, 16, producer);
setRand(cctx, ZSTD_c_ldmMinMatch, ZSTD_LDM_MINMATCH_MIN, 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, setRand(cctx, ZSTD_c_ldmBucketSizeLog, 0, ZSTD_LDM_BUCKETSIZELOG_MAX,
state); producer);
setRand(cctx, ZSTD_c_ldmHashRateLog, ZSTD_LDM_HASHRATELOG_MIN, setRand(cctx, ZSTD_c_ldmHashRateLog, ZSTD_LDM_HASHRATELOG_MIN,
ZSTD_LDM_HASHRATELOG_MAX, state); ZSTD_LDM_HASHRATELOG_MAX, producer);
/* Set misc parameters */ /* Set misc parameters */
setRand(cctx, ZSTD_c_nbWorkers, 0, 2, state); setRand(cctx, ZSTD_c_nbWorkers, 0, 2, producer);
setRand(cctx, ZSTD_c_rsyncable, 0, 1, state); setRand(cctx, ZSTD_c_rsyncable, 0, 1, producer);
setRand(cctx, ZSTD_c_forceMaxWindow, 0, 1, state); setRand(cctx, ZSTD_c_forceMaxWindow, 0, 1, producer);
setRand(cctx, ZSTD_c_literalCompressionMode, 0, 2, state); setRand(cctx, ZSTD_c_literalCompressionMode, 0, 2, producer);
setRand(cctx, ZSTD_c_forceAttachDict, 0, 2, state); setRand(cctx, ZSTD_c_forceAttachDict, 0, 2, producer);
if (FUZZ_rand32(state, 0, 1) == 0) { if (FUZZ_dataProducer_uint32Range(producer, 0, 1) == 0) {
setRand(cctx, ZSTD_c_srcSizeHint, ZSTD_SRCSIZEHINT_MIN, 2 * srcSize, state); 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 dictSize = MAX(srcSize / 8, 1024);
size_t const totalSampleSize = dictSize * 11; 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) { for (sample = 0; sample < nbSamples; ++sample) {
size_t const remaining = totalSampleSize - pos; 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 limit = MIN(srcSize - offset, remaining);
size_t const toCopy = MIN(limit, remaining / (nbSamples - sample)); size_t const toCopy = MIN(limit, remaining / (nbSamples - sample));
memcpy(samples + pos, src + offset, toCopy); memcpy(samples + pos, src + offset, toCopy);

View File

@@ -17,17 +17,18 @@
#define ZSTD_STATIC_LINKING_ONLY #define ZSTD_STATIC_LINKING_ONLY
#include "zstd.h" #include "zstd.h"
#include "fuzz_data_producer.h"
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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_compressionParameters FUZZ_randomCParams(size_t srcSize, FUZZ_dataProducer_t *producer);
ZSTD_frameParameters FUZZ_randomFParams(uint32_t *state); ZSTD_frameParameters FUZZ_randomFParams(FUZZ_dataProducer_t *producer);
ZSTD_parameters FUZZ_randomParams(size_t srcSize, uint32_t *state); ZSTD_parameters FUZZ_randomParams(size_t srcSize, FUZZ_dataProducer_t *producer);
typedef struct { typedef struct {
void* buff; void* buff;
@@ -38,7 +39,7 @@ typedef struct {
* NOTE: Don't use this to train production dictionaries, it is only optimized * NOTE: Don't use this to train production dictionaries, it is only optimized
* for speed, and doesn't care about dictionary quality. * 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 #ifdef __cplusplus