]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
decompressBound() tests
authorYann Collet <cyan@fb.com>
Fri, 16 Dec 2022 23:32:19 +0000 (15:32 -0800)
committerYann Collet <cyan@fb.com>
Fri, 16 Dec 2022 23:43:26 +0000 (15:43 -0800)
fixed an overflow in an intermediate result on 32-bit platform.
Checked that the new test catch this bug in 32-bit mode.

lib/decompress/zstd_decompress.c
tests/fuzzer.c

index e95b8822fe3b789e5945352625751594afd1f137..57f220d0cdd93d29252f879789b22ad2a0aa0842 100644 (file)
@@ -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;
     }
 }
index e15cf0648e77fa8c63dbb3230151851eeaeae5b8..c3322852317ff6107fcdd2dd86614f84aa813f15 100644 (file)
@@ -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<nbBlocks; blockNb++) {
+            ZSTD_inBuffer in = { input, sizeof(input), 0 };
+            CHECK_Z( ZSTD_compressStream(cctx, &out, &in) );
+            CHECK_EQ( ZSTD_flushStream(cctx, &out), 0 );
+        }
+        CHECK_EQ( ZSTD_endStream(cctx, &out), 0 );
+        CHECK( ZSTD_decompressBound(outBuffer, out.pos) > 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;