From: Yann Collet Date: Fri, 16 Dec 2022 23:32:19 +0000 (-0800) Subject: decompressBound() tests X-Git-Tag: v1.5.4^2~97^2~1 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=ea24b886673a1e154a81d71222d130f65da7a0ed;p=thirdparty%2Fzstd.git decompressBound() tests fixed an overflow in an intermediate result on 32-bit platform. Checked that the new test catch this bug in 32-bit mode. --- diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index e95b8822f..57f220d0c 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -785,7 +785,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize frameSizeInfo.compressedSize = (size_t)(ip - ipstart); frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) ? zfh.frameContentSize - : nbBlocks * zfh.blockSizeMax; + : (unsigned long long)nbBlocks * zfh.blockSizeMax; return frameSizeInfo; } } diff --git a/tests/fuzzer.c b/tests/fuzzer.c index e15cf0648..c33228523 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -485,6 +485,61 @@ static void test_compressBound(int tnb) DISPLAYLEVEL(3, "OK \n"); } +static void test_decompressBound(int tnb) +{ + DISPLAYLEVEL(3, "test%3i : decompressBound : ", tnb); + + // Simple compression, with size : should provide size; + { const char example[] = "abcd"; + char cBuffer[ZSTD_COMPRESSBOUND(sizeof(example))]; + size_t const cSize = ZSTD_compress(cBuffer, sizeof(cBuffer), example, sizeof(example), 0); + CHECK_Z(cSize); + { size_t const dbSize = ZSTD_decompressBound(cBuffer, cSize); + CHECK_Z(dbSize); + CHECK_EQ(dbSize, sizeof(example)); + } } + + // Simple small compression without size : should provide 1 block size + { char cBuffer[ZSTD_COMPRESSBOUND(0)]; + ZSTD_outBuffer out = { cBuffer, sizeof(cBuffer), 0 }; + ZSTD_inBuffer in = { NULL, 0, 0 }; + ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + assert(cctx); + CHECK_Z( ZSTD_initCStream(cctx, 0) ); + CHECK_Z( ZSTD_compressStream(cctx, &out, &in) ); + CHECK_EQ( ZSTD_endStream(cctx, &out), 0 ); + CHECK_EQ( ZSTD_decompressBound(cBuffer, out.pos), ZSTD_BLOCKSIZE_MAX ); + ZSTD_freeCCtx(cctx); + } + + // Attempt to overflow 32-bit intermediate multiplication result + // This requires dBound >= 4 GB, aka 2^32. + // This requires 2^32 / 2^17 = 2^15 blocks + // => create 2^15 blocks (can be empty, or just 1 byte). + { const char input[] = "a"; + size_t const nbBlocks = (1 << 15) + 1; + size_t blockNb; + size_t const outCapacity = 1 << 18; // large margin + char* const outBuffer = malloc (outCapacity); + ZSTD_outBuffer out = { outBuffer, outCapacity, 0 }; + ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + assert(cctx); + assert(outBuffer); + CHECK_Z( ZSTD_initCStream(cctx, 0) ); + for (blockNb=0; blockNb 0x100000000LLU /* 4 GB */ ); + ZSTD_freeCCtx(cctx); + free(outBuffer); + } + + DISPLAYLEVEL(3, "OK \n"); +} + static int basicUnitTests(U32 const seed, double compressibility) { size_t const CNBuffSize = 5 MB; @@ -533,6 +588,8 @@ static int basicUnitTests(U32 const seed, double compressibility) test_compressBound(testNb++); + test_decompressBound(testNb++); + DISPLAYLEVEL(3, "test%3u : ZSTD_adjustCParams : ", testNb++); { ZSTD_compressionParameters params;