[fuzz] Allow zero sized buffers for streaming fuzzers (#1945)
* Allow zero sized buffers in `stream_decompress`. Ensure that we never have two zero sized buffers in a row so we guarantee forwards progress. * Make case 4 in `stream_round_trip` do a zero sized buffers call followed by a full call to guarantee forwards progress. * Fix `limitCopy()` in legacy decoders. * Fix memcpy in `zstdmt_compress.c`. Catches the bug fixed in PR #1939
This commit is contained in:
parent
03ffda7b88
commit
d1cc9d2797
@ -1714,9 +1714,11 @@ static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, u
|
||||
assert(mtctx->doneJobID < mtctx->nextJobID);
|
||||
assert(cSize >= mtctx->jobs[wJobID].dstFlushed);
|
||||
assert(mtctx->jobs[wJobID].dstBuff.start != NULL);
|
||||
memcpy((char*)output->dst + output->pos,
|
||||
(const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
|
||||
toFlush);
|
||||
if (toFlush > 0) {
|
||||
memcpy((char*)output->dst + output->pos,
|
||||
(const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
|
||||
toFlush);
|
||||
}
|
||||
output->pos += toFlush;
|
||||
mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */
|
||||
|
||||
|
@ -3407,7 +3407,9 @@ static size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* zbc, const void* src, s
|
||||
static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||
{
|
||||
size_t length = MIN(maxDstSize, srcSize);
|
||||
memcpy(dst, src, length);
|
||||
if (length > 0) {
|
||||
memcpy(dst, src, length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -3791,7 +3791,9 @@ static size_t ZBUFFv05_blockHeaderSize = 3;
|
||||
static size_t ZBUFFv05_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||
{
|
||||
size_t length = MIN(maxDstSize, srcSize);
|
||||
memcpy(dst, src, length);
|
||||
if (length > 0) {
|
||||
memcpy(dst, src, length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -4000,7 +4000,9 @@ size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* zbd)
|
||||
MEM_STATIC size_t ZBUFFv06_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||
{
|
||||
size_t length = MIN(dstCapacity, srcSize);
|
||||
memcpy(dst, src, length);
|
||||
if (length > 0) {
|
||||
memcpy(dst, src, length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -4378,7 +4378,9 @@ size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* zbd)
|
||||
MEM_STATIC size_t ZBUFFv07_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||
{
|
||||
size_t const length = MIN(dstCapacity, srcSize);
|
||||
memcpy(dst, src, length);
|
||||
if (length > 0) {
|
||||
memcpy(dst, src, length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -27,27 +27,36 @@ static ZSTD_DStream *dstream = NULL;
|
||||
static void* buf = NULL;
|
||||
uint32_t seed;
|
||||
|
||||
static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer)
|
||||
static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer, uint32_t min)
|
||||
{
|
||||
ZSTD_outBuffer buffer = { buf, 0, 0 };
|
||||
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, kBufSize));
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, min, kBufSize));
|
||||
FUZZ_ASSERT(buffer.size <= kBufSize);
|
||||
|
||||
if (buffer.size == 0) {
|
||||
buffer.dst = NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
FUZZ_dataProducer_t *producer,
|
||||
uint32_t min)
|
||||
{
|
||||
ZSTD_inBuffer buffer = { *src, 0, 0 };
|
||||
|
||||
FUZZ_ASSERT(*size > 0);
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, *size));
|
||||
buffer.size = (FUZZ_dataProducer_uint32Range(producer, min, *size));
|
||||
FUZZ_ASSERT(buffer.size <= *size);
|
||||
*src += buffer.size;
|
||||
*size -= buffer.size;
|
||||
|
||||
if (buffer.size == 0) {
|
||||
buffer.src = NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -56,6 +65,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t 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);
|
||||
/* Guarantee forward progress by refusing to generate 2 zero sized
|
||||
* buffers in a row. */
|
||||
int prevInWasZero = 0;
|
||||
int prevOutWasZero = 0;
|
||||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
@ -72,9 +85,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
|
||||
ZSTD_inBuffer in = makeInBuffer(&src, &size, producer, prevInWasZero ? 1 : 0);
|
||||
prevInWasZero = in.size == 0;
|
||||
while (in.pos != in.size) {
|
||||
ZSTD_outBuffer out = makeOutBuffer(producer);
|
||||
ZSTD_outBuffer out = makeOutBuffer(producer, prevOutWasZero ? 1 : 0);
|
||||
prevOutWasZero = out.size == 0;
|
||||
size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
|
||||
if (ZSTD_isError(rc)) goto error;
|
||||
}
|
||||
|
@ -96,6 +96,13 @@ static size_t compress(uint8_t *dst, size_t capacity,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
ZSTD_inBuffer nullIn = { NULL, 0, 0 };
|
||||
ZSTD_outBuffer nullOut = { NULL, 0, 0 };
|
||||
size_t const ret = ZSTD_compressStream2(cctx, &nullOut, &nullIn, ZSTD_e_continue);
|
||||
FUZZ_ZASSERT(ret);
|
||||
}
|
||||
/* fall-through */
|
||||
default: {
|
||||
size_t const ret =
|
||||
ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);
|
||||
|
Loading…
Reference in New Issue
Block a user