]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
Fix ZSTD_getOffsetInfo() when nbSeq == 0
authorNick Terrell <terrelln@fb.com>
Thu, 2 Feb 2023 18:53:08 +0000 (10:53 -0800)
committerNick Terrell <nickrterrell@gmail.com>
Thu, 2 Feb 2023 22:26:41 +0000 (14:26 -0800)
In 32-bit mode, ZSTD_getOffsetInfo() can be called when nbSeq == 0, and
in this case the offset table is uninitialized. The function should just
return 0 for both values, because there are no sequences.

Credit to OSS-Fuzz

lib/decompress/zstd_decompress_block.c

index f8a7963a98c92884e922dbb7a946b5efa152a63b..0a06a021e15d0d584a6b2c052688668d7fad6b58 100644 (file)
@@ -2008,24 +2008,29 @@ typedef struct {
  *           as well as the maximum number additional bits required.
  */
 static ZSTD_OffsetInfo
-ZSTD_getOffsetInfo(const ZSTD_seqSymbol* offTable)
+ZSTD_getOffsetInfo(const ZSTD_seqSymbol* offTable, int nbSeq)
 {
-    const void* ptr = offTable;
-    U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
-    const ZSTD_seqSymbol* table = offTable + 1;
-    U32 const max = 1 << tableLog;
-    U32 u;
     ZSTD_OffsetInfo info = {0, 0};
-    DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
+    /* If nbSeq == 0, then the offTable is uninitialized, but we have
+     * no sequences, so both values should be 0.
+     */
+    if (nbSeq != 0) {
+        const void* ptr = offTable;
+        U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog;
+        const ZSTD_seqSymbol* table = offTable + 1;
+        U32 const max = 1 << tableLog;
+        U32 u;
+        DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog);
 
-    assert(max <= (1 << OffFSELog));  /* max not too large */
-    for (u=0; u<max; u++) {
-        info.maxNbAdditionalBits = MAX(info.maxNbAdditionalBits, table[u].nbAdditionalBits);
-        if (table[u].nbAdditionalBits > 22) info.longOffsetShare += 1;
-    }
+        assert(max <= (1 << OffFSELog));  /* max not too large */
+        for (u=0; u<max; u++) {
+            info.maxNbAdditionalBits = MAX(info.maxNbAdditionalBits, table[u].nbAdditionalBits);
+            if (table[u].nbAdditionalBits > 22) info.longOffsetShare += 1;
+        }
 
-    assert(tableLog <= OffFSELog);
-    info.longOffsetShare <<= (OffFSELog - tableLog);  /* scale to OffFSELog */
+        assert(tableLog <= OffFSELog);
+        info.longOffsetShare <<= (OffFSELog - tableLog);  /* scale to OffFSELog */
+    }
 
     return info;
 }
@@ -2126,7 +2131,7 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
          * NOTE: could probably use a larger nbSeq limit
          */
         if (isLongOffset || (!usePrefetchDecoder && (totalHistorySize > (1u << 24)) && (nbSeq > 8))) {
-            ZSTD_OffsetInfo const info = ZSTD_getOffsetInfo(dctx->OFTptr);
+            ZSTD_OffsetInfo const info = ZSTD_getOffsetInfo(dctx->OFTptr, nbSeq);
             if (isLongOffset && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN) {
                 /* If isLongOffset, but the maximum number of additional bits that we see in our table is small
                  * enough, then we know it is impossible to have too long an offset in this block, so we can