diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index f018271765d..09896a931e2 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -2112,7 +2112,9 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ip += seqHSize; srcSize -= seqHSize; - RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF((dst == NULL || dstCapacity == 0) && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(MEM_64bits() && sizeof(size_t) == sizeof(void*) && (size_t)(-1) - (size_t)dst < (size_t)(1 << 20), dstSize_tooSmall, + "invalid dst"); /* If we could potentially have long offsets, or we might want to use the prefetch decoder, * compute information about the share of long offsets, and the maximum nbAdditionalBits. diff --git a/tests/fuzz/block_decompress.c b/tests/fuzz/block_decompress.c index e4767b3f509..9cc6005c3b2 100644 --- a/tests/fuzz/block_decompress.c +++ b/tests/fuzz/block_decompress.c @@ -13,6 +13,7 @@ * decompression function to ensure the decompressor never crashes. */ +#include "fuzz_data_producer.h" #define ZSTD_STATIC_LINKING_ONLY #include @@ -28,11 +29,12 @@ static size_t bufSize = 0; int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) { size_t const neededBufSize = ZSTD_BLOCKSIZE_MAX; + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); /* Allocate all buffers and contexts if not already allocated */ if (neededBufSize > bufSize) { free(rBuf); - rBuf = FUZZ_malloc(neededBufSize); + rBuf = FUZZ_malloc_rand(neededBufSize, producer); bufSize = neededBufSize; } if (!dctx) { @@ -42,6 +44,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) ZSTD_decompressBegin(dctx); ZSTD_decompressBlock(dctx, rBuf, neededBufSize, src, size); + FUZZ_dataProducer_free(producer); + #ifndef STATEFUL_FUZZING ZSTD_freeDCtx(dctx); dctx = NULL; #endif diff --git a/tests/fuzz/fuzz_data_producer.c b/tests/fuzz/fuzz_data_producer.c index a93e8ba950b..bf846b68f72 100644 --- a/tests/fuzz/fuzz_data_producer.c +++ b/tests/fuzz/fuzz_data_producer.c @@ -8,6 +8,7 @@ * You may select, at your option, one of the above-listed licenses. */ +#include "fuzz_helpers.h" #include "fuzz_data_producer.h" struct FUZZ_dataProducer_s{ diff --git a/tests/fuzz/fuzz_data_producer.h b/tests/fuzz/fuzz_data_producer.h index 8ca501f9b09..f488ceb991b 100644 --- a/tests/fuzz/fuzz_data_producer.h +++ b/tests/fuzz/fuzz_data_producer.h @@ -24,7 +24,6 @@ #include #include -#include "fuzz_helpers.h" /* Struct used for maintaining the state of the data */ typedef struct FUZZ_dataProducer_s FUZZ_dataProducer_t; diff --git a/tests/fuzz/fuzz_helpers.c b/tests/fuzz/fuzz_helpers.c index 1b6ad9736cb..f47ff2eb4ff 100644 --- a/tests/fuzz/fuzz_helpers.c +++ b/tests/fuzz/fuzz_helpers.c @@ -23,6 +23,22 @@ void* FUZZ_malloc(size_t size) return NULL; } +void* FUZZ_malloc_rand(size_t size, FUZZ_dataProducer_t *producer) +{ + if (size > 0) { + void* const mem = malloc(size); + FUZZ_ASSERT(mem); + return mem; + } else { + uintptr_t ptr = 0; + /* Add +- 1M 50% of the time */ + if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) + FUZZ_dataProducer_int32Range(producer, -1000000, 1000000); + return (void*)ptr; + } + +} + int FUZZ_memcmp(void const* lhs, void const* rhs, size_t size) { if (size == 0) { diff --git a/tests/fuzz/fuzz_helpers.h b/tests/fuzz/fuzz_helpers.h index aaf4c1df45e..f21ec47516e 100644 --- a/tests/fuzz/fuzz_helpers.h +++ b/tests/fuzz/fuzz_helpers.h @@ -19,6 +19,7 @@ #include "fuzz.h" #include "xxhash.h" #include "zstd.h" +#include "fuzz_data_producer.h" #include #include #include @@ -62,6 +63,12 @@ extern "C" { */ void* FUZZ_malloc(size_t size); +/** + * malloc except returns random pointer for zero sized data and FUZZ_ASSERT + * that malloc doesn't fail. + */ +void* FUZZ_malloc_rand(size_t size, FUZZ_dataProducer_t *producer); + /** * memcmp but accepts NULL. */