* 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
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 */
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;
}
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;
}
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;
}
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;
}
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;
}
/* 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 */
}
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;
}
}
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);