[lib] Fix NULL pointer dereference
When the output buffer is `NULL` with size 0, but the frame content size is non-zero, we will write to the NULL pointer because our bounds check underflowed. This was exposed by a recent PR that allowed an empty frame into the single-pass shortcut in streaming mode. * Fix the bug. * Fix another NULL dereference in zstd-v1. * Overflow checks in 32-bit mode. * Add a dedicated test. * Expose the bug in the dedicated simple_decompress fuzzer. * Switch all mallocs in fuzzers to return NULL for size=0. * Fix a new timeout in a fuzzer. Neither clang nor gcc show a decompression speed regression on x86-64. On x86-32 clang is slightly positive and gcc loses 2.5% of speed. Credit to OSS-Fuzz.dev
parent
ad8dbae1b7
commit
5717bd39ee
|
@ -709,7 +709,9 @@ FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, c
|
|||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
if (input != NULL) {
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
}
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
|
|
@ -665,15 +665,15 @@ size_t ZSTD_execSequenceEnd(BYTE* op,
|
|||
{
|
||||
BYTE* const oLitEnd = op + sequence.litLength;
|
||||
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
|
||||
BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
|
||||
const BYTE* const iLitEnd = *litPtr + sequence.litLength;
|
||||
const BYTE* match = oLitEnd - sequence.offset;
|
||||
BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
|
||||
|
||||
/* bounds checks */
|
||||
assert(oLitEnd < oMatchEnd);
|
||||
RETURN_ERROR_IF(oMatchEnd > oend, dstSize_tooSmall, "last match must fit within dstBuffer");
|
||||
RETURN_ERROR_IF(iLitEnd > litLimit, corruption_detected, "try to read beyond literal buffer");
|
||||
/* bounds checks : careful of address space overflow in 32-bit mode */
|
||||
RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer");
|
||||
RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer");
|
||||
assert(op < op + sequenceLength);
|
||||
assert(oLitEnd < op + sequenceLength);
|
||||
|
||||
/* copy literals */
|
||||
ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap);
|
||||
|
@ -709,16 +709,27 @@ size_t ZSTD_execSequence(BYTE* op,
|
|||
BYTE* const oLitEnd = op + sequence.litLength;
|
||||
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
|
||||
BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
|
||||
BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
|
||||
BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */
|
||||
const BYTE* const iLitEnd = *litPtr + sequence.litLength;
|
||||
const BYTE* match = oLitEnd - sequence.offset;
|
||||
|
||||
/* Errors and uncommon cases handled here. */
|
||||
assert(oLitEnd < oMatchEnd);
|
||||
if (UNLIKELY(iLitEnd > litLimit || oMatchEnd > oend_w))
|
||||
assert(op != NULL /* Precondition */);
|
||||
assert(oend_w < oend /* No underflow */);
|
||||
/* Handle edge cases in a slow path:
|
||||
* - Read beyond end of literals
|
||||
* - Match end is within WILDCOPY_OVERLIMIT of oend
|
||||
* - 32-bit mode and the match length overflows
|
||||
*/
|
||||
if (UNLIKELY(
|
||||
iLitEnd > litLimit ||
|
||||
oMatchEnd > oend_w ||
|
||||
(MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH)))
|
||||
return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd);
|
||||
|
||||
/* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */
|
||||
assert(op <= oLitEnd /* No overflow */);
|
||||
assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */);
|
||||
assert(oMatchEnd <= oend /* No underflow */);
|
||||
assert(iLitEnd <= litLimit /* Literal length is in bounds */);
|
||||
assert(oLitEnd <= oend_w /* Can wildcopy literals */);
|
||||
assert(oMatchEnd <= oend_w /* Can wildcopy matches */);
|
||||
|
@ -968,6 +979,7 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
|||
ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
|
||||
ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
|
||||
ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
|
||||
assert(dst != NULL);
|
||||
|
||||
ZSTD_STATIC_ASSERT(
|
||||
BIT_DStream_unfinished < BIT_DStream_completed &&
|
||||
|
@ -1043,8 +1055,10 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
|
|||
/* last literal segment */
|
||||
{ size_t const lastLLSize = litEnd - litPtr;
|
||||
RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (op != NULL) {
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
return op-ostart;
|
||||
|
@ -1093,6 +1107,7 @@ ZSTD_decompressSequencesLong_body(
|
|||
seqState.prefixStart = prefixStart;
|
||||
seqState.pos = (size_t)(op-prefixStart);
|
||||
seqState.dictEnd = dictEnd;
|
||||
assert(dst != NULL);
|
||||
assert(iend >= ip);
|
||||
RETURN_ERROR_IF(
|
||||
ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)),
|
||||
|
@ -1134,8 +1149,10 @@ ZSTD_decompressSequencesLong_body(
|
|||
/* last literal segment */
|
||||
{ size_t const lastLLSize = litEnd - litPtr;
|
||||
RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (op != NULL) {
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
return op-ostart;
|
||||
|
@ -1255,7 +1272,6 @@ ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
size_t
|
||||
ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
|
@ -1297,6 +1313,8 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
|||
ip += seqHSize;
|
||||
srcSize -= seqHSize;
|
||||
|
||||
RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled");
|
||||
|
||||
#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \
|
||||
!defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG)
|
||||
if ( !usePrefetchDecoder
|
||||
|
|
|
@ -1078,7 +1078,7 @@ static size_t HUF_decompress_usingDTable( /* -3% slower when non static */
|
|||
BYTE* const ostart = (BYTE*) dst;
|
||||
BYTE* op = ostart;
|
||||
BYTE* const omax = op + maxDstSize;
|
||||
BYTE* const olimit = omax-15;
|
||||
BYTE* const olimit = maxDstSize < 15 ? op : omax-15;
|
||||
|
||||
const void* ptr = DTable;
|
||||
const HUF_DElt* const dt = (const HUF_DElt*)(ptr)+1;
|
||||
|
@ -1483,7 +1483,9 @@ static size_t ZSTDv01_getcBlockSize(const void* src, size_t srcSize, blockProper
|
|||
static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||
{
|
||||
if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall);
|
||||
memcpy(dst, src, srcSize);
|
||||
if (srcSize > 0) {
|
||||
memcpy(dst, src, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
|
@ -1541,7 +1543,9 @@ static size_t ZSTDv01_decodeLiteralsBlock(void* ctx,
|
|||
size_t rleSize = litbp.origSize;
|
||||
if (rleSize>maxDstSize) return ERROR(dstSize_tooSmall);
|
||||
if (!srcSize) return ERROR(srcSize_wrong);
|
||||
memset(oend - rleSize, *ip, rleSize);
|
||||
if (rleSize > 0) {
|
||||
memset(oend - rleSize, *ip, rleSize);
|
||||
}
|
||||
*litStart = oend - rleSize;
|
||||
*litSize = rleSize;
|
||||
ip++;
|
||||
|
@ -1901,8 +1905,10 @@ static size_t ZSTD_decompressSequences(
|
|||
{
|
||||
size_t lastLLSize = litEnd - litPtr;
|
||||
if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
|
||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2836,7 +2836,9 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie
|
|||
static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||
{
|
||||
if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall);
|
||||
memcpy(dst, src, srcSize);
|
||||
if (srcSize > 0) {
|
||||
memcpy(dst, src, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
|
@ -3229,8 +3231,10 @@ static size_t ZSTD_decompressSequences(
|
|||
size_t lastLLSize = litEnd - litPtr;
|
||||
if (litPtr > litEnd) return ERROR(corruption_detected);
|
||||
if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
|
||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2477,7 +2477,9 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie
|
|||
static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||
{
|
||||
if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall);
|
||||
memcpy(dst, src, srcSize);
|
||||
if (srcSize > 0) {
|
||||
memcpy(dst, src, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
|
@ -2870,8 +2872,10 @@ static size_t ZSTD_decompressSequences(
|
|||
size_t lastLLSize = litEnd - litPtr;
|
||||
if (litPtr > litEnd) return ERROR(corruption_detected);
|
||||
if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
|
||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2603,7 +2603,9 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie
|
|||
static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
|
||||
{
|
||||
if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall);
|
||||
memcpy(dst, src, srcSize);
|
||||
if (srcSize > 0) {
|
||||
memcpy(dst, src, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
|
@ -3008,8 +3010,10 @@ static size_t ZSTD_decompressSequences(
|
|||
size_t lastLLSize = litEnd - litPtr;
|
||||
if (litPtr > litEnd) return ERROR(corruption_detected);
|
||||
if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
|
||||
if (op != litPtr) memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
if (op != litPtr) memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3362,8 +3362,10 @@ static size_t ZSTDv05_decompressSequences(
|
|||
size_t lastLLSize = litEnd - litPtr;
|
||||
if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */
|
||||
if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
return op-ostart;
|
||||
|
|
|
@ -3501,8 +3501,10 @@ static size_t ZSTDv06_decompressSequences(
|
|||
{ size_t const lastLLSize = litEnd - litPtr;
|
||||
if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */
|
||||
if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall);
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
return op-ostart;
|
||||
|
|
|
@ -3272,7 +3272,9 @@ static size_t ZSTDv07_getcBlockSize(const void* src, size_t srcSize, blockProper
|
|||
static size_t ZSTDv07_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||
{
|
||||
if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall);
|
||||
memcpy(dst, src, srcSize);
|
||||
if (srcSize > 0) {
|
||||
memcpy(dst, src, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
}
|
||||
|
||||
|
@ -3714,8 +3716,10 @@ static size_t ZSTDv07_decompressSequences(
|
|||
{ size_t const lastLLSize = litEnd - litPtr;
|
||||
/* if (litPtr > litEnd) return ERROR(corruption_detected); */ /* too many literals already used */
|
||||
if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
if (lastLLSize > 0) {
|
||||
memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
}
|
||||
}
|
||||
|
||||
return op-ostart;
|
||||
|
@ -3776,7 +3780,9 @@ ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockS
|
|||
static size_t ZSTDv07_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length)
|
||||
{
|
||||
if (length > dstCapacity) return ERROR(dstSize_tooSmall);
|
||||
memset(dst, byte, length);
|
||||
if (length > 0) {
|
||||
memset(dst, byte, length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ FUZZ_ARFLAGS := $(ARFLAGS)
|
|||
FUZZ_TARGET_FLAGS = $(FUZZ_CPPFLAGS) $(FUZZ_CXXFLAGS) $(FUZZ_LDFLAGS)
|
||||
|
||||
FUZZ_HEADERS := fuzz_helpers.h fuzz.h zstd_helpers.h fuzz_data_producer.h
|
||||
FUZZ_SRC := $(PRGDIR)/util.c zstd_helpers.c fuzz_data_producer.c
|
||||
FUZZ_SRC := $(PRGDIR)/util.c fuzz_helpers.c zstd_helpers.c fuzz_data_producer.c
|
||||
|
||||
ZSTDCOMMON_SRC := $(ZSTDDIR)/common/*.c
|
||||
ZSTDCOMP_SRC := $(ZSTDDIR)/compress/*.c
|
||||
|
|
|
@ -32,9 +32,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (neededBufSize > bufSize) {
|
||||
free(rBuf);
|
||||
rBuf = malloc(neededBufSize);
|
||||
rBuf = FUZZ_malloc(neededBufSize);
|
||||
bufSize = neededBufSize;
|
||||
FUZZ_ASSERT(rBuf);
|
||||
}
|
||||
if (!dctx) {
|
||||
dctx = ZSTD_createDCtx();
|
||||
|
|
|
@ -43,7 +43,9 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
|||
FUZZ_ZASSERT(ret);
|
||||
if (ret == 0) {
|
||||
FUZZ_ASSERT(resultCapacity >= srcSize);
|
||||
memcpy(result, src, srcSize);
|
||||
if (srcSize > 0) {
|
||||
memcpy(result, src, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
}
|
||||
ZSTD_decompressBegin(dctx);
|
||||
|
@ -67,10 +69,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
if (neededBufSize > bufSize || !cBuf || !rBuf) {
|
||||
free(cBuf);
|
||||
free(rBuf);
|
||||
cBuf = malloc(neededBufSize);
|
||||
rBuf = malloc(neededBufSize);
|
||||
cBuf = FUZZ_malloc(neededBufSize);
|
||||
rBuf = FUZZ_malloc(neededBufSize);
|
||||
bufSize = neededBufSize;
|
||||
FUZZ_ASSERT(cBuf && rBuf);
|
||||
}
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
|
@ -87,7 +88,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
cLevel);
|
||||
FUZZ_ZASSERT(result);
|
||||
FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
FUZZ_dataProducer_free(producer);
|
||||
#ifndef STATEFUL_FUZZING
|
||||
|
|
|
@ -55,8 +55,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
|
||||
{
|
||||
size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
|
||||
void* rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
void* rBuf = FUZZ_malloc(bufSize);
|
||||
if (ddict) {
|
||||
ZSTD_decompress_usingDDict(dctx, rBuf, bufSize, src, size, ddict);
|
||||
} else {
|
||||
|
|
|
@ -79,11 +79,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
DEBUGLOG(2, "Dict content type %d", dct);
|
||||
DEBUGLOG(2, "Dict size %u", (unsigned)size);
|
||||
|
||||
void* const rBuf = malloc(size);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
void* const rBuf = FUZZ_malloc(size);
|
||||
size_t const cBufSize = ZSTD_compressBound(size);
|
||||
void* const cBuf = malloc(cBufSize);
|
||||
FUZZ_ASSERT(cBuf);
|
||||
void* const cBuf = FUZZ_malloc(cBufSize);
|
||||
|
||||
size_t const cSize =
|
||||
compress(cBuf, cBufSize, src, size, src, size, dlm, dct, refPrefix);
|
||||
|
@ -95,7 +93,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
size_t const rSize =
|
||||
decompress(rBuf, size, cBuf, cSize, src, size, dlm, dct, refPrefix);
|
||||
FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
|
||||
|
||||
out:
|
||||
free(cBuf);
|
||||
|
|
|
@ -84,7 +84,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
size = FUZZ_dataProducer_reserveDataPrefix(producer);
|
||||
|
||||
size_t const rBufSize = size;
|
||||
void* rBuf = malloc(rBufSize);
|
||||
void* rBuf = FUZZ_malloc(rBufSize);
|
||||
size_t cBufSize = ZSTD_compressBound(size) * 2;
|
||||
void *cBuf;
|
||||
/* Half of the time fuzz with a 1 byte smaller output size.
|
||||
|
@ -92,7 +92,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
* giving us 4 bytes of overhead.
|
||||
*/
|
||||
cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
cBuf = malloc(cBufSize);
|
||||
cBuf = FUZZ_malloc(cBufSize);
|
||||
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
|
@ -108,7 +108,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t 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!");
|
||||
FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
free(rBuf);
|
||||
free(cBuf);
|
||||
|
|
|
@ -16,9 +16,7 @@ struct FUZZ_dataProducer_s{
|
|||
};
|
||||
|
||||
FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size) {
|
||||
FUZZ_dataProducer_t *producer = malloc(sizeof(FUZZ_dataProducer_t));
|
||||
|
||||
FUZZ_ASSERT(producer != NULL);
|
||||
FUZZ_dataProducer_t *producer = FUZZ_malloc(sizeof(FUZZ_dataProducer_t));
|
||||
|
||||
producer->data = data;
|
||||
producer->size = size;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2020, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#include "fuzz_helpers.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void* FUZZ_malloc(size_t size)
|
||||
{
|
||||
if (size > 0) {
|
||||
void* const mem = malloc(size);
|
||||
FUZZ_ASSERT(mem);
|
||||
return mem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int FUZZ_memcmp(void const* lhs, void const* rhs, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
return memcmp(lhs, rhs, size);
|
||||
}
|
|
@ -56,6 +56,17 @@ extern "C" {
|
|||
#define FUZZ_STATIC static
|
||||
#endif
|
||||
|
||||
/**
|
||||
* malloc except return NULL for zero sized data and FUZZ_ASSERT
|
||||
* that malloc doesn't fail.
|
||||
*/
|
||||
void* FUZZ_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* memcmp but accepts NULL.
|
||||
*/
|
||||
int FUZZ_memcmp(void const* lhs, void const* rhs, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -41,8 +41,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
FUZZ_ASSERT(cctx);
|
||||
}
|
||||
|
||||
void *rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
void *rBuf = FUZZ_malloc(bufSize);
|
||||
ZSTD_compressCCtx(cctx, rBuf, bufSize, src, size, cLevel);
|
||||
free(rBuf);
|
||||
FUZZ_dataProducer_free(producer);
|
||||
|
|
|
@ -35,8 +35,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
}
|
||||
|
||||
size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
|
||||
void *rBuf = malloc(bufSize);
|
||||
FUZZ_ASSERT(rBuf);
|
||||
void *rBuf = FUZZ_malloc(bufSize);
|
||||
|
||||
ZSTD_decompressDCtx(dctx, rBuf, bufSize, src, size);
|
||||
free(rBuf);
|
||||
|
|
|
@ -70,7 +70,7 @@ static size_t roundTripTest(void *result, size_t resultCapacity,
|
|||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
size_t const rBufSize = size;
|
||||
void* rBuf = malloc(rBufSize);
|
||||
void* rBuf = FUZZ_malloc(rBufSize);
|
||||
size_t cBufSize = ZSTD_compressBound(size);
|
||||
void* cBuf;
|
||||
|
||||
|
@ -85,9 +85,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
*/
|
||||
cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
|
||||
|
||||
cBuf = malloc(cBufSize);
|
||||
|
||||
FUZZ_ASSERT(cBuf && rBuf);
|
||||
cBuf = FUZZ_malloc(cBufSize);
|
||||
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
|
@ -103,7 +101,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t 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!");
|
||||
FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
free(rBuf);
|
||||
free(cBuf);
|
||||
|
|
|
@ -76,9 +76,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
|
||||
/* Allocate all buffers and contexts if not already allocated */
|
||||
if (!buf) {
|
||||
buf = malloc(kBufSize);
|
||||
FUZZ_ASSERT(buf);
|
||||
}
|
||||
buf = FUZZ_malloc(kBufSize);
|
||||
}
|
||||
|
||||
if (!dstream) {
|
||||
dstream = ZSTD_createDStream();
|
||||
|
@ -99,7 +98,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
ZSTD_inBuffer in = makeInBuffer(&src, &size, producer, prevInWasZero ? 1 : 0);
|
||||
prevInWasZero = in.size == 0;
|
||||
while (in.pos != in.size) {
|
||||
if (!stableOutBuffer || FUZZ_dataProducer_uint32Range(producer, 0, 100) == 55) {
|
||||
if (!stableOutBuffer || prevOutWasZero || FUZZ_dataProducer_uint32Range(producer, 0, 100) == 55) {
|
||||
out = makeOutBuffer(producer, prevOutWasZero ? 1 : 0);
|
||||
}
|
||||
prevOutWasZero = out.size == 0;
|
||||
|
|
|
@ -146,10 +146,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
if (neededBufSize > bufSize) {
|
||||
free(cBuf);
|
||||
free(rBuf);
|
||||
cBuf = (uint8_t*)malloc(neededBufSize);
|
||||
rBuf = (uint8_t*)malloc(neededBufSize);
|
||||
cBuf = (uint8_t*)FUZZ_malloc(neededBufSize);
|
||||
rBuf = (uint8_t*)FUZZ_malloc(neededBufSize);
|
||||
bufSize = neededBufSize;
|
||||
FUZZ_ASSERT(cBuf && rBuf);
|
||||
}
|
||||
if (!cctx) {
|
||||
cctx = ZSTD_createCCtx();
|
||||
|
@ -166,7 +165,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
|||
ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize);
|
||||
FUZZ_ZASSERT(rSize);
|
||||
FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size");
|
||||
FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
|
||||
FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
|
||||
}
|
||||
|
||||
FUZZ_dataProducer_free(producer);
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
|
||||
{
|
||||
ZSTD_frameHeader zfh;
|
||||
if (size == 0) {
|
||||
src = NULL;
|
||||
}
|
||||
/* You can fuzz any helper functions here that are fast, and take zstd
|
||||
* compressed data as input. E.g. don't expect the input to be a dictionary,
|
||||
* so don't fuzz ZSTD_getDictID_fromDict().
|
||||
|
|
|
@ -106,14 +106,13 @@ FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, FUZZ_dataProducer_t *pro
|
|||
{
|
||||
size_t const dictSize = MAX(srcSize / 8, 1024);
|
||||
size_t const totalSampleSize = dictSize * 11;
|
||||
FUZZ_dict_t dict = { malloc(dictSize), dictSize };
|
||||
char* const samples = (char*)malloc(totalSampleSize);
|
||||
FUZZ_dict_t dict = { FUZZ_malloc(dictSize), dictSize };
|
||||
char* const samples = (char*)FUZZ_malloc(totalSampleSize);
|
||||
unsigned nbSamples = 100;
|
||||
size_t* const samplesSizes = (size_t*)malloc(sizeof(size_t) * nbSamples);
|
||||
size_t* const samplesSizes = (size_t*)FUZZ_malloc(sizeof(size_t) * nbSamples);
|
||||
size_t pos = 0;
|
||||
size_t sample = 0;
|
||||
ZDICT_fastCover_params_t params;
|
||||
FUZZ_ASSERT(dict.buff && samples && samplesSizes);
|
||||
|
||||
for (sample = 0; sample < nbSamples; ++sample) {
|
||||
size_t const remaining = totalSampleSize - pos;
|
||||
|
@ -123,7 +122,6 @@ FUZZ_dict_t FUZZ_train(void const* src, size_t srcSize, FUZZ_dataProducer_t *pro
|
|||
memcpy(samples + pos, src + offset, toCopy);
|
||||
pos += toCopy;
|
||||
samplesSizes[sample] = toCopy;
|
||||
|
||||
}
|
||||
memset(samples + pos, 0, totalSampleSize - pos);
|
||||
|
||||
|
|
|
@ -538,6 +538,12 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
|||
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : decompress into NULL buffer : ", testNb++);
|
||||
{ size_t const r = ZSTD_decompress(NULL, 0, compressedBuffer, compressedBufferSize);
|
||||
if (!ZSTD_isError(r)) goto _output_error;
|
||||
if (ZSTD_getErrorCode(r) != ZSTD_error_dstSize_tooSmall) goto _output_error; }
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : ZSTD_decompressBound test with content size missing : ", testNb++);
|
||||
{ /* create compressed buffer with content size missing */
|
||||
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
|
|
Loading…
Reference in New Issue