|  | @@ -1,5 +1,5 @@
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  | - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
 | 
	
		
			
				|  |  | + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
 | 
	
		
			
				|  |  |   * All rights reserved.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * This source code is licensed under both the BSD-style license (found in the
 | 
	
	
		
			
				|  | @@ -15,14 +15,14 @@
 | 
	
		
			
				|  |  |  *  Dependencies
 | 
	
		
			
				|  |  |  *********************************************************/
 | 
	
		
			
				|  |  |  #include <string.h>      /* memcpy, memmove, memset */
 | 
	
		
			
				|  |  | -#include "compiler.h"    /* prefetch */
 | 
	
		
			
				|  |  | -#include "cpu.h"         /* bmi2 */
 | 
	
		
			
				|  |  | -#include "mem.h"         /* low level memory routines */
 | 
	
		
			
				|  |  | +#include "../common/compiler.h"    /* prefetch */
 | 
	
		
			
				|  |  | +#include "../common/cpu.h"         /* bmi2 */
 | 
	
		
			
				|  |  | +#include "../common/mem.h"         /* low level memory routines */
 | 
	
		
			
				|  |  |  #define FSE_STATIC_LINKING_ONLY
 | 
	
		
			
				|  |  | -#include "fse.h"
 | 
	
		
			
				|  |  | +#include "../common/fse.h"
 | 
	
		
			
				|  |  |  #define HUF_STATIC_LINKING_ONLY
 | 
	
		
			
				|  |  | -#include "huf.h"
 | 
	
		
			
				|  |  | -#include "zstd_internal.h"
 | 
	
		
			
				|  |  | +#include "../common/huf.h"
 | 
	
		
			
				|  |  | +#include "../common/zstd_internal.h"
 | 
	
		
			
				|  |  |  #include "zstd_decompress_internal.h"   /* ZSTD_DCtx */
 | 
	
		
			
				|  |  |  #include "zstd_ddict.h"  /* ZSTD_DDictDictContent */
 | 
	
		
			
				|  |  |  #include "zstd_decompress_block.h"
 | 
	
	
		
			
				|  | @@ -56,7 +56,7 @@ static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
 | 
	
		
			
				|  |  |  size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
 | 
	
		
			
				|  |  |                            blockProperties_t* bpPtr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong);
 | 
	
		
			
				|  |  | +    RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      {   U32 const cBlockHeader = MEM_readLE24(src);
 | 
	
		
			
				|  |  |          U32 const cSize = cBlockHeader >> 3;
 | 
	
	
		
			
				|  | @@ -64,7 +64,7 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
 | 
	
		
			
				|  |  |          bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
 | 
	
		
			
				|  |  |          bpPtr->origSize = cSize;   /* only useful for RLE */
 | 
	
		
			
				|  |  |          if (bpPtr->blockType == bt_rle) return 1;
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, "");
 | 
	
		
			
				|  |  |          return cSize;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -80,7 +80,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                            const void* src, size_t srcSize)   /* note : srcSize < BLOCKSIZE */
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      DEBUGLOG(5, "ZSTD_decodeLiteralsBlock");
 | 
	
		
			
				|  |  | -    RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected);
 | 
	
		
			
				|  |  | +    RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      {   const BYTE* const istart = (const BYTE*) src;
 | 
	
		
			
				|  |  |          symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
 | 
	
	
		
			
				|  | @@ -89,7 +89,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |          case set_repeat:
 | 
	
		
			
				|  |  |              DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block");
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, "");
 | 
	
		
			
				|  |  |              /* fall-through */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          case set_compressed:
 | 
	
	
		
			
				|  | @@ -121,8 +121,8 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                      litCSize = (lhc >> 22) + ((size_t)istart[4] << 10);
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected);
 | 
	
		
			
				|  |  | -                RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected);
 | 
	
		
			
				|  |  | +                RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
 | 
	
		
			
				|  |  | +                RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  /* prefetch huffman table if cold */
 | 
	
		
			
				|  |  |                  if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) {
 | 
	
	
		
			
				|  | @@ -160,7 +160,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected);
 | 
	
		
			
				|  |  | +                RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  dctx->litPtr = dctx->litBuffer;
 | 
	
		
			
				|  |  |                  dctx->litSize = litSize;
 | 
	
	
		
			
				|  | @@ -190,7 +190,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) {  /* risk reading beyond src buffer with wildcopy */
 | 
	
		
			
				|  |  | -                    RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected);
 | 
	
		
			
				|  |  | +                    RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, "");
 | 
	
		
			
				|  |  |                      memcpy(dctx->litBuffer, istart+lhSize, litSize);
 | 
	
		
			
				|  |  |                      dctx->litPtr = dctx->litBuffer;
 | 
	
		
			
				|  |  |                      dctx->litSize = litSize;
 | 
	
	
		
			
				|  | @@ -222,7 +222,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                      RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4");
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected);
 | 
	
		
			
				|  |  | +                RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
 | 
	
		
			
				|  |  |                  memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
 | 
	
		
			
				|  |  |                  dctx->litPtr = dctx->litBuffer;
 | 
	
		
			
				|  |  |                  dctx->litSize = litSize;
 | 
	
	
		
			
				|  | @@ -440,8 +440,8 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
 | 
	
		
			
				|  |  |      switch(type)
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |      case set_rle :
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(!srcSize, srcSize_wrong);
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF((*(const BYTE*)src) > max, corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(!srcSize, srcSize_wrong, "");
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF((*(const BYTE*)src) > max, corruption_detected, "");
 | 
	
		
			
				|  |  |          {   U32 const symbol = *(const BYTE*)src;
 | 
	
		
			
				|  |  |              U32 const baseline = baseValue[symbol];
 | 
	
		
			
				|  |  |              U32 const nbBits = nbAdditionalBits[symbol];
 | 
	
	
		
			
				|  | @@ -453,7 +453,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
 | 
	
		
			
				|  |  |          *DTablePtr = defaultTable;
 | 
	
		
			
				|  |  |          return 0;
 | 
	
		
			
				|  |  |      case set_repeat:
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(!flagRepeatTable, corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, "");
 | 
	
		
			
				|  |  |          /* prefetch FSE table if used */
 | 
	
		
			
				|  |  |          if (ddictIsCold && (nbSeq > 24 /* heuristic */)) {
 | 
	
		
			
				|  |  |              const void* const pStart = *DTablePtr;
 | 
	
	
		
			
				|  | @@ -465,8 +465,8 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb
 | 
	
		
			
				|  |  |          {   unsigned tableLog;
 | 
	
		
			
				|  |  |              S16 norm[MaxSeq+1];
 | 
	
		
			
				|  |  |              size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected);
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(tableLog > maxLog, corruption_detected);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, "");
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, "");
 | 
	
		
			
				|  |  |              ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog);
 | 
	
		
			
				|  |  |              *DTablePtr = DTableSpace;
 | 
	
		
			
				|  |  |              return headerSize;
 | 
	
	
		
			
				|  | @@ -487,28 +487,28 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
 | 
	
		
			
				|  |  |      DEBUGLOG(5, "ZSTD_decodeSeqHeaders");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* check */
 | 
	
		
			
				|  |  | -    RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong);
 | 
	
		
			
				|  |  | +    RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* SeqHead */
 | 
	
		
			
				|  |  |      nbSeq = *ip++;
 | 
	
		
			
				|  |  |      if (!nbSeq) {
 | 
	
		
			
				|  |  |          *nbSeqPtr=0;
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(srcSize != 1, srcSize_wrong);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, "");
 | 
	
		
			
				|  |  |          return 1;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (nbSeq > 0x7F) {
 | 
	
		
			
				|  |  |          if (nbSeq == 0xFF) {
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, "");
 | 
	
		
			
				|  |  |              nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
 | 
	
		
			
				|  |  |          } else {
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(ip >= iend, srcSize_wrong);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(ip >= iend, srcSize_wrong, "");
 | 
	
		
			
				|  |  |              nbSeq = ((nbSeq-0x80)<<8) + *ip++;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      *nbSeqPtr = nbSeq;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* FSE table descriptors */
 | 
	
		
			
				|  |  | -    RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong); /* minimum possible size: 1 byte for symbol encoding types */
 | 
	
		
			
				|  |  | +    RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */
 | 
	
		
			
				|  |  |      {   symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
 | 
	
		
			
				|  |  |          symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
 | 
	
		
			
				|  |  |          symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
 | 
	
	
		
			
				|  | @@ -521,7 +521,7 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
 | 
	
		
			
				|  |  |                                                        LL_base, LL_bits,
 | 
	
		
			
				|  |  |                                                        LL_defaultDTable, dctx->fseEntropy,
 | 
	
		
			
				|  |  |                                                        dctx->ddictIsCold, nbSeq);
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed");
 | 
	
		
			
				|  |  |              ip += llhSize;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -531,7 +531,7 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
 | 
	
		
			
				|  |  |                                                        OF_base, OF_bits,
 | 
	
		
			
				|  |  |                                                        OF_defaultDTable, dctx->fseEntropy,
 | 
	
		
			
				|  |  |                                                        dctx->ddictIsCold, nbSeq);
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed");
 | 
	
		
			
				|  |  |              ip += ofhSize;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -541,7 +541,7 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
 | 
	
		
			
				|  |  |                                                        ML_base, ML_bits,
 | 
	
		
			
				|  |  |                                                        ML_defaultDTable, dctx->fseEntropy,
 | 
	
		
			
				|  |  |                                                        dctx->ddictIsCold, nbSeq);
 | 
	
		
			
				|  |  | -            RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected);
 | 
	
		
			
				|  |  | +            RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed");
 | 
	
		
			
				|  |  |              ip += mlhSize;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -580,7 +580,7 @@ typedef struct {
 | 
	
		
			
				|  |  |   *  Precondition: *ip <= *op
 | 
	
		
			
				|  |  |   *  Postcondition: *op - *op >= 8
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -static void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) {
 | 
	
		
			
				|  |  | +HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) {
 | 
	
		
			
				|  |  |      assert(*ip <= *op);
 | 
	
		
			
				|  |  |      if (offset < 8) {
 | 
	
		
			
				|  |  |          /* close range match, overlap */
 | 
	
	
		
			
				|  | @@ -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);
 | 
	
	
		
			
				|  | @@ -683,7 +683,7 @@ size_t ZSTD_execSequenceEnd(BYTE* op,
 | 
	
		
			
				|  |  |      /* copy Match */
 | 
	
		
			
				|  |  |      if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
 | 
	
		
			
				|  |  |          /* offset beyond prefix */
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, "");
 | 
	
		
			
				|  |  |          match = dictEnd - (prefixStart-match);
 | 
	
		
			
				|  |  |          if (match + sequence.matchLength <= dictEnd) {
 | 
	
		
			
				|  |  |              memmove(oLitEnd, match, sequence.matchLength);
 | 
	
	
		
			
				|  | @@ -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 (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 */);
 | 
	
	
		
			
				|  | @@ -729,7 +740,7 @@ size_t ZSTD_execSequence(BYTE* op,
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      assert(WILDCOPY_OVERLENGTH >= 16);
 | 
	
		
			
				|  |  |      ZSTD_copy16(op, (*litPtr));
 | 
	
		
			
				|  |  | -    if (sequence.litLength > 16) {
 | 
	
		
			
				|  |  | +    if (UNLIKELY(sequence.litLength > 16)) {
 | 
	
		
			
				|  |  |          ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      op = oLitEnd;
 | 
	
	
		
			
				|  | @@ -738,7 +749,7 @@ size_t ZSTD_execSequence(BYTE* op,
 | 
	
		
			
				|  |  |      /* Copy Match */
 | 
	
		
			
				|  |  |      if (sequence.offset > (size_t)(oLitEnd - prefixStart)) {
 | 
	
		
			
				|  |  |          /* offset beyond prefix -> go into extDict */
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, "");
 | 
	
		
			
				|  |  |          match = dictEnd + (match - prefixStart);
 | 
	
		
			
				|  |  |          if (match + sequence.matchLength <= dictEnd) {
 | 
	
		
			
				|  |  |              memmove(oLitEnd, match, sequence.matchLength);
 | 
	
	
		
			
				|  | @@ -760,7 +771,7 @@ size_t ZSTD_execSequence(BYTE* op,
 | 
	
		
			
				|  |  |      /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy
 | 
	
		
			
				|  |  |       * without overlap checking.
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    if (sequence.offset >= WILDCOPY_VECLEN) {
 | 
	
		
			
				|  |  | +    if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) {
 | 
	
		
			
				|  |  |          /* We bet on a full wildcopy for matches, since we expect matches to be
 | 
	
		
			
				|  |  |           * longer than literals (in general). In silesia, ~10% of matches are longer
 | 
	
		
			
				|  |  |           * than 16 bytes.
 | 
	
	
		
			
				|  | @@ -802,6 +813,14 @@ ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
 | 
	
		
			
				|  |  |      DStatePtr->state = DInfo.nextState + lowBits;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +FORCE_INLINE_TEMPLATE void
 | 
	
		
			
				|  |  | +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD_seqSymbol const DInfo)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    U32 const nbBits = DInfo.nbBits;
 | 
	
		
			
				|  |  | +    size_t const lowBits = BIT_readBits(bitD, nbBits);
 | 
	
		
			
				|  |  | +    DStatePtr->state = DInfo.nextState + lowBits;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum
 | 
	
		
			
				|  |  |   * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1)
 | 
	
		
			
				|  |  |   * bits before reloading. This value is the maximum number of bytes we read
 | 
	
	
		
			
				|  | @@ -813,25 +832,26 @@ ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD)
 | 
	
		
			
				|  |  |          : 0)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e;
 | 
	
		
			
				|  |  | +typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
 | 
	
		
			
				|  |  |  FORCE_INLINE_TEMPLATE seq_t
 | 
	
		
			
				|  |  | -ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
 | 
	
		
			
				|  |  | +ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      seq_t seq;
 | 
	
		
			
				|  |  | -    U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
 | 
	
		
			
				|  |  | -    U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
 | 
	
		
			
				|  |  | -    U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
 | 
	
		
			
				|  |  | -    U32 const totalBits = llBits+mlBits+ofBits;
 | 
	
		
			
				|  |  | -    U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
 | 
	
		
			
				|  |  | -    U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
 | 
	
		
			
				|  |  | -    U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
 | 
	
		
			
				|  |  | +    ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state];
 | 
	
		
			
				|  |  | +    ZSTD_seqSymbol const mlDInfo = seqState->stateML.table[seqState->stateML.state];
 | 
	
		
			
				|  |  | +    ZSTD_seqSymbol const ofDInfo = seqState->stateOffb.table[seqState->stateOffb.state];
 | 
	
		
			
				|  |  | +    U32 const llBase = llDInfo.baseValue;
 | 
	
		
			
				|  |  | +    U32 const mlBase = mlDInfo.baseValue;
 | 
	
		
			
				|  |  | +    U32 const ofBase = ofDInfo.baseValue;
 | 
	
		
			
				|  |  | +    BYTE const llBits = llDInfo.nbAdditionalBits;
 | 
	
		
			
				|  |  | +    BYTE const mlBits = mlDInfo.nbAdditionalBits;
 | 
	
		
			
				|  |  | +    BYTE const ofBits = ofDInfo.nbAdditionalBits;
 | 
	
		
			
				|  |  | +    BYTE const totalBits = llBits+mlBits+ofBits;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* sequence */
 | 
	
		
			
				|  |  |      {   size_t offset;
 | 
	
		
			
				|  |  | -        if (!ofBits)
 | 
	
		
			
				|  |  | -            offset = 0;
 | 
	
		
			
				|  |  | -        else {
 | 
	
		
			
				|  |  | +        if (ofBits > 1) {
 | 
	
		
			
				|  |  |              ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
 | 
	
		
			
				|  |  |              ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
 | 
	
		
			
				|  |  |              assert(ofBits <= MaxOff);
 | 
	
	
		
			
				|  | @@ -845,59 +865,138 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets)
 | 
	
		
			
				|  |  |                  offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/);   /* <=  (ZSTD_WINDOWLOG_MAX-1) bits */
 | 
	
		
			
				|  |  |                  if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (ofBits <= 1) {
 | 
	
		
			
				|  |  | -            offset += (llBase==0);
 | 
	
		
			
				|  |  | -            if (offset) {
 | 
	
		
			
				|  |  | -                size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
 | 
	
		
			
				|  |  | -                temp += !temp;   /* 0 is not valid; input is corrupted; force offset to 1 */
 | 
	
		
			
				|  |  | -                if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
 | 
	
		
			
				|  |  | -                seqState->prevOffset[1] = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | -                seqState->prevOffset[0] = offset = temp;
 | 
	
		
			
				|  |  | -            } else {  /* offset == 0 */
 | 
	
		
			
				|  |  | -                offset = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  |              seqState->prevOffset[2] = seqState->prevOffset[1];
 | 
	
		
			
				|  |  |              seqState->prevOffset[1] = seqState->prevOffset[0];
 | 
	
		
			
				|  |  |              seqState->prevOffset[0] = offset;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            U32 const ll0 = (llBase == 0);
 | 
	
		
			
				|  |  | +            if (LIKELY((ofBits == 0))) {
 | 
	
		
			
				|  |  | +                if (LIKELY(!ll0))
 | 
	
		
			
				|  |  | +                    offset = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | +                else {
 | 
	
		
			
				|  |  | +                    offset = seqState->prevOffset[1];
 | 
	
		
			
				|  |  | +                    seqState->prevOffset[1] = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | +                    seqState->prevOffset[0] = offset;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1);
 | 
	
		
			
				|  |  | +                {   size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
 | 
	
		
			
				|  |  | +                    temp += !temp;   /* 0 is not valid; input is corrupted; force offset to 1 */
 | 
	
		
			
				|  |  | +                    if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
 | 
	
		
			
				|  |  | +                    seqState->prevOffset[1] = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | +                    seqState->prevOffset[0] = offset = temp;
 | 
	
		
			
				|  |  | +        }   }   }
 | 
	
		
			
				|  |  |          seq.offset = offset;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    seq.matchLength = mlBase
 | 
	
		
			
				|  |  | -                    + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/) : 0);  /* <=  16 bits */
 | 
	
		
			
				|  |  | +    seq.matchLength = mlBase;
 | 
	
		
			
				|  |  | +    if (mlBits > 0)
 | 
	
		
			
				|  |  | +        seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
 | 
	
		
			
				|  |  |          BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  | -    if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
 | 
	
		
			
				|  |  | +    if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
 | 
	
		
			
				|  |  |          BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  |      /* Ensure there are enough bits to read the rest of data in 64-bit mode. */
 | 
	
		
			
				|  |  |      ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    seq.litLength = llBase
 | 
	
		
			
				|  |  | -                  + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits/*>0*/) : 0);    /* <=  16 bits */
 | 
	
		
			
				|  |  | +    seq.litLength = llBase;
 | 
	
		
			
				|  |  | +    if (llBits > 0)
 | 
	
		
			
				|  |  | +        seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (MEM_32bits())
 | 
	
		
			
				|  |  |          BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u",
 | 
	
		
			
				|  |  |                  (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /* ANS state update */
 | 
	
		
			
				|  |  | -    ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */
 | 
	
		
			
				|  |  | -    ZSTD_updateFseState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */
 | 
	
		
			
				|  |  | -    if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */
 | 
	
		
			
				|  |  | -    ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */
 | 
	
		
			
				|  |  | +    if (prefetch == ZSTD_p_prefetch) {
 | 
	
		
			
				|  |  | +        size_t const pos = seqState->pos + seq.litLength;
 | 
	
		
			
				|  |  | +        const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
 | 
	
		
			
				|  |  | +        seq.match = matchBase + pos - seq.offset;  /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
 | 
	
		
			
				|  |  | +                                                    * No consequence though : no memory access will occur, offset is only used for prefetching */
 | 
	
		
			
				|  |  | +        seqState->pos = pos + seq.matchLength;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* ANS state update
 | 
	
		
			
				|  |  | +     * gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo().
 | 
	
		
			
				|  |  | +     * clang-9.2.0 does 7% worse with ZSTD_updateFseState().
 | 
	
		
			
				|  |  | +     * Naturally it seems like ZSTD_updateFseStateWithDInfo() should be the
 | 
	
		
			
				|  |  | +     * better option, so it is the default for other compilers. But, if you
 | 
	
		
			
				|  |  | +     * measure that it is worse, please put up a pull request.
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +#if defined(__GNUC__) && !defined(__clang__)
 | 
	
		
			
				|  |  | +        const int kUseUpdateFseState = 1;
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +        const int kUseUpdateFseState = 0;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +        if (kUseUpdateFseState) {
 | 
	
		
			
				|  |  | +            ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */
 | 
	
		
			
				|  |  | +            ZSTD_updateFseState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */
 | 
	
		
			
				|  |  | +            if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */
 | 
	
		
			
				|  |  | +            ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llDInfo);    /* <=  9 bits */
 | 
	
		
			
				|  |  | +            ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlDInfo);    /* <=  9 bits */
 | 
	
		
			
				|  |  | +            if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */
 | 
	
		
			
				|  |  | +            ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofDInfo);  /* <=  8 bits */
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return seq;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 | 
	
		
			
				|  |  | +static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    size_t const windowSize = dctx->fParams.windowSize;
 | 
	
		
			
				|  |  | +    /* No dictionary used. */
 | 
	
		
			
				|  |  | +    if (dctx->dictContentEndForFuzzing == NULL) return 0;
 | 
	
		
			
				|  |  | +    /* Dictionary is our prefix. */
 | 
	
		
			
				|  |  | +    if (prefixStart == dctx->dictContentBeginForFuzzing) return 1;
 | 
	
		
			
				|  |  | +    /* Dictionary is not our ext-dict. */
 | 
	
		
			
				|  |  | +    if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0;
 | 
	
		
			
				|  |  | +    /* Dictionary is not within our window size. */
 | 
	
		
			
				|  |  | +    if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0;
 | 
	
		
			
				|  |  | +    /* Dictionary is active. */
 | 
	
		
			
				|  |  | +    return 1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +MEM_STATIC void ZSTD_assertValidSequence(
 | 
	
		
			
				|  |  | +        ZSTD_DCtx const* dctx,
 | 
	
		
			
				|  |  | +        BYTE const* op, BYTE const* oend,
 | 
	
		
			
				|  |  | +        seq_t const seq,
 | 
	
		
			
				|  |  | +        BYTE const* prefixStart, BYTE const* virtualStart)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    size_t const windowSize = dctx->fParams.windowSize;
 | 
	
		
			
				|  |  | +    size_t const sequenceSize = seq.litLength + seq.matchLength;
 | 
	
		
			
				|  |  | +    BYTE const* const oLitEnd = op + seq.litLength;
 | 
	
		
			
				|  |  | +    DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u",
 | 
	
		
			
				|  |  | +            (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset);
 | 
	
		
			
				|  |  | +    assert(op <= oend);
 | 
	
		
			
				|  |  | +    assert((size_t)(oend - op) >= sequenceSize);
 | 
	
		
			
				|  |  | +    assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX);
 | 
	
		
			
				|  |  | +    if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) {
 | 
	
		
			
				|  |  | +        size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing);
 | 
	
		
			
				|  |  | +        /* Offset must be within the dictionary. */
 | 
	
		
			
				|  |  | +        assert(seq.offset <= (size_t)(oLitEnd - virtualStart));
 | 
	
		
			
				|  |  | +        assert(seq.offset <= windowSize + dictSize);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        /* Offset must be within our window. */
 | 
	
		
			
				|  |  | +        assert(seq.offset <= windowSize);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
 | 
	
		
			
				|  |  |  FORCE_INLINE_TEMPLATE size_t
 | 
	
		
			
				|  |  |  DONT_VECTORIZE
 | 
	
		
			
				|  |  |  ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                 void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                           const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                         const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                         const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                         const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      const BYTE* ip = (const BYTE*)seqStart;
 | 
	
		
			
				|  |  |      const BYTE* const iend = ip + seqSize;
 | 
	
	
		
			
				|  | @@ -910,46 +1009,104 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |      const BYTE* const vBase = (const BYTE*) (dctx->virtualStart);
 | 
	
		
			
				|  |  |      const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
 | 
	
		
			
				|  |  |      DEBUGLOG(5, "ZSTD_decompressSequences_body");
 | 
	
		
			
				|  |  | +    (void)frame;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* Regen sequences */
 | 
	
		
			
				|  |  |      if (nbSeq) {
 | 
	
		
			
				|  |  |          seqState_t seqState;
 | 
	
		
			
				|  |  | +        size_t error = 0;
 | 
	
		
			
				|  |  |          dctx->fseEntropy = 1;
 | 
	
		
			
				|  |  |          { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
 | 
	
		
			
				|  |  |          RETURN_ERROR_IF(
 | 
	
		
			
				|  |  |              ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)),
 | 
	
		
			
				|  |  | -            corruption_detected);
 | 
	
		
			
				|  |  | +            corruption_detected, "");
 | 
	
		
			
				|  |  |          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 &&
 | 
	
		
			
				|  |  |                  BIT_DStream_endOfBuffer < BIT_DStream_completed &&
 | 
	
		
			
				|  |  |                  BIT_DStream_completed < BIT_DStream_overflow);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
 | 
	
		
			
				|  |  | -            nbSeq--;
 | 
	
		
			
				|  |  | -            {   seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset);
 | 
	
		
			
				|  |  | -                size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
 | 
	
		
			
				|  |  | -                DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
 | 
	
		
			
				|  |  | -                if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
 | 
	
		
			
				|  |  | -                op += oneSeqSize;
 | 
	
		
			
				|  |  | -        }   }
 | 
	
		
			
				|  |  | +#if defined(__GNUC__) && defined(__x86_64__)
 | 
	
		
			
				|  |  | +        /* Align the decompression loop to 32 + 16 bytes.
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression
 | 
	
		
			
				|  |  | +         * speed swings based on the alignment of the decompression loop. This
 | 
	
		
			
				|  |  | +         * performance swing is caused by parts of the decompression loop falling
 | 
	
		
			
				|  |  | +         * out of the DSB. The entire decompression loop should fit in the DSB,
 | 
	
		
			
				|  |  | +         * when it can't we get much worse performance. You can measure if you've
 | 
	
		
			
				|  |  | +         * hit the good case or the bad case with this perf command for some
 | 
	
		
			
				|  |  | +         * compressed file test.zst:
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         *   perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \
 | 
	
		
			
				|  |  | +         *             -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         * If you see most cycles served out of the MITE you've hit the bad case.
 | 
	
		
			
				|  |  | +         * If you see most cycles served out of the DSB you've hit the good case.
 | 
	
		
			
				|  |  | +         * If it is pretty even then you may be in an okay case.
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         * I've been able to reproduce this issue on the following CPUs:
 | 
	
		
			
				|  |  | +         *   - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9
 | 
	
		
			
				|  |  | +         *               Use Instruments->Counters to get DSB/MITE cycles.
 | 
	
		
			
				|  |  | +         *               I never got performance swings, but I was able to
 | 
	
		
			
				|  |  | +         *               go from the good case of mostly DSB to half of the
 | 
	
		
			
				|  |  | +         *               cycles served from MITE.
 | 
	
		
			
				|  |  | +         *   - Coffeelake: Intel i9-9900k
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         * I haven't been able to reproduce the instability or DSB misses on any
 | 
	
		
			
				|  |  | +         * of the following CPUS:
 | 
	
		
			
				|  |  | +         *   - Haswell
 | 
	
		
			
				|  |  | +         *   - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH
 | 
	
		
			
				|  |  | +         *   - Skylake
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         * If you are seeing performance stability this script can help test.
 | 
	
		
			
				|  |  | +         * It tests on 4 commits in zstd where I saw performance change.
 | 
	
		
			
				|  |  | +         *
 | 
	
		
			
				|  |  | +         *   https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        __asm__(".p2align 5");
 | 
	
		
			
				|  |  | +        __asm__("nop");
 | 
	
		
			
				|  |  | +        __asm__(".p2align 4");
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +        for ( ; ; ) {
 | 
	
		
			
				|  |  | +            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch);
 | 
	
		
			
				|  |  | +            size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd);
 | 
	
		
			
				|  |  | +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
 | 
	
		
			
				|  |  | +            assert(!ZSTD_isError(oneSeqSize));
 | 
	
		
			
				|  |  | +            if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +            DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize);
 | 
	
		
			
				|  |  | +            BIT_reloadDStream(&(seqState.DStream));
 | 
	
		
			
				|  |  | +            /* gcc and clang both don't like early returns in this loop.
 | 
	
		
			
				|  |  | +             * gcc doesn't like early breaks either.
 | 
	
		
			
				|  |  | +             * Instead save an error and report it at the end.
 | 
	
		
			
				|  |  | +             * When there is an error, don't increment op, so we don't
 | 
	
		
			
				|  |  | +             * overwrite.
 | 
	
		
			
				|  |  | +             */
 | 
	
		
			
				|  |  | +            if (UNLIKELY(ZSTD_isError(oneSeqSize))) error = oneSeqSize;
 | 
	
		
			
				|  |  | +            else op += oneSeqSize;
 | 
	
		
			
				|  |  | +            if (UNLIKELY(!--nbSeq)) break;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /* check if reached exact end */
 | 
	
		
			
				|  |  |          DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq);
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(nbSeq, corruption_detected);
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected);
 | 
	
		
			
				|  |  | +        if (ZSTD_isError(error)) return error;
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(nbSeq, corruption_detected, "");
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, "");
 | 
	
		
			
				|  |  |          /* save reps for next block */
 | 
	
		
			
				|  |  |          { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]); }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* 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;
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
 | 
	
		
			
				|  |  | +        if (op != NULL) {
 | 
	
		
			
				|  |  | +            memcpy(op, litPtr, lastLLSize);
 | 
	
		
			
				|  |  | +            op += lastLLSize;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return op-ostart;
 | 
	
	
		
			
				|  | @@ -959,99 +1116,21 @@ static size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressSequences_default(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                   void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                             const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                           const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                           const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                           const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +    return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
 | 
	
		
			
				|  |  | -FORCE_INLINE_TEMPLATE seq_t
 | 
	
		
			
				|  |  | -ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const longOffsets)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    seq_t seq;
 | 
	
		
			
				|  |  | -    U32 const llBits = seqState->stateLL.table[seqState->stateLL.state].nbAdditionalBits;
 | 
	
		
			
				|  |  | -    U32 const mlBits = seqState->stateML.table[seqState->stateML.state].nbAdditionalBits;
 | 
	
		
			
				|  |  | -    U32 const ofBits = seqState->stateOffb.table[seqState->stateOffb.state].nbAdditionalBits;
 | 
	
		
			
				|  |  | -    U32 const totalBits = llBits+mlBits+ofBits;
 | 
	
		
			
				|  |  | -    U32 const llBase = seqState->stateLL.table[seqState->stateLL.state].baseValue;
 | 
	
		
			
				|  |  | -    U32 const mlBase = seqState->stateML.table[seqState->stateML.state].baseValue;
 | 
	
		
			
				|  |  | -    U32 const ofBase = seqState->stateOffb.table[seqState->stateOffb.state].baseValue;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* sequence */
 | 
	
		
			
				|  |  | -    {   size_t offset;
 | 
	
		
			
				|  |  | -        if (!ofBits)
 | 
	
		
			
				|  |  | -            offset = 0;
 | 
	
		
			
				|  |  | -        else {
 | 
	
		
			
				|  |  | -            ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1);
 | 
	
		
			
				|  |  | -            ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5);
 | 
	
		
			
				|  |  | -            assert(ofBits <= MaxOff);
 | 
	
		
			
				|  |  | -            if (MEM_32bits() && longOffsets) {
 | 
	
		
			
				|  |  | -                U32 const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN_32-1);
 | 
	
		
			
				|  |  | -                offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
 | 
	
		
			
				|  |  | -                if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  | -                if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
 | 
	
		
			
				|  |  | -            } else {
 | 
	
		
			
				|  |  | -                offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits);   /* <=  (ZSTD_WINDOWLOG_MAX-1) bits */
 | 
	
		
			
				|  |  | -                if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (ofBits <= 1) {
 | 
	
		
			
				|  |  | -            offset += (llBase==0);
 | 
	
		
			
				|  |  | -            if (offset) {
 | 
	
		
			
				|  |  | -                size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
 | 
	
		
			
				|  |  | -                temp += !temp;   /* 0 is not valid; input is corrupted; force offset to 1 */
 | 
	
		
			
				|  |  | -                if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
 | 
	
		
			
				|  |  | -                seqState->prevOffset[1] = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | -                seqState->prevOffset[0] = offset = temp;
 | 
	
		
			
				|  |  | -            } else {
 | 
	
		
			
				|  |  | -                offset = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -            seqState->prevOffset[2] = seqState->prevOffset[1];
 | 
	
		
			
				|  |  | -            seqState->prevOffset[1] = seqState->prevOffset[0];
 | 
	
		
			
				|  |  | -            seqState->prevOffset[0] = offset;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        seq.offset = offset;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    seq.matchLength = mlBase + ((mlBits>0) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0);  /* <=  16 bits */
 | 
	
		
			
				|  |  | -    if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32))
 | 
	
		
			
				|  |  | -        BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  | -    if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog)))
 | 
	
		
			
				|  |  | -        BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  | -    /* Verify that there is enough bits to read the rest of the data in 64-bit mode. */
 | 
	
		
			
				|  |  | -    ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    seq.litLength = llBase + ((llBits>0) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0);    /* <=  16 bits */
 | 
	
		
			
				|  |  | -    if (MEM_32bits())
 | 
	
		
			
				|  |  | -        BIT_reloadDStream(&seqState->DStream);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    {   size_t const pos = seqState->pos + seq.litLength;
 | 
	
		
			
				|  |  | -        const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart;
 | 
	
		
			
				|  |  | -        seq.match = matchBase + pos - seq.offset;  /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted.
 | 
	
		
			
				|  |  | -                                                    * No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */
 | 
	
		
			
				|  |  | -        seqState->pos = pos + seq.matchLength;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* ANS state update */
 | 
	
		
			
				|  |  | -    ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */
 | 
	
		
			
				|  |  | -    ZSTD_updateFseState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */
 | 
	
		
			
				|  |  | -    if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */
 | 
	
		
			
				|  |  | -    ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return seq;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  FORCE_INLINE_TEMPLATE size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressSequencesLong_body(
 | 
	
		
			
				|  |  |                                 ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                 void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                           const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                         const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                         const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                         const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      const BYTE* ip = (const BYTE*)seqStart;
 | 
	
		
			
				|  |  |      const BYTE* const iend = ip + seqSize;
 | 
	
	
		
			
				|  | @@ -1063,6 +1142,7 @@ ZSTD_decompressSequencesLong_body(
 | 
	
		
			
				|  |  |      const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart);
 | 
	
		
			
				|  |  |      const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart);
 | 
	
		
			
				|  |  |      const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
 | 
	
		
			
				|  |  | +    (void)frame;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* Regen sequences */
 | 
	
		
			
				|  |  |      if (nbSeq) {
 | 
	
	
		
			
				|  | @@ -1078,36 +1158,45 @@ 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)),
 | 
	
		
			
				|  |  | -            corruption_detected);
 | 
	
		
			
				|  |  | +            corruption_detected, "");
 | 
	
		
			
				|  |  |          ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
 | 
	
		
			
				|  |  |          ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
 | 
	
		
			
				|  |  |          ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /* prepare in advance */
 | 
	
		
			
				|  |  |          for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNb<seqAdvance); seqNb++) {
 | 
	
		
			
				|  |  | -            sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
 | 
	
		
			
				|  |  | +            sequences[seqNb] = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
 | 
	
		
			
				|  |  |              PREFETCH_L1(sequences[seqNb].match); PREFETCH_L1(sequences[seqNb].match + sequences[seqNb].matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(seqNb<seqAdvance, corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(seqNb<seqAdvance, corruption_detected, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /* decode and decompress */
 | 
	
		
			
				|  |  |          for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNb<nbSeq) ; seqNb++) {
 | 
	
		
			
				|  |  | -            seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
 | 
	
		
			
				|  |  | +            seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_prefetch);
 | 
	
		
			
				|  |  |              size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
 | 
	
		
			
				|  |  | +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
 | 
	
		
			
				|  |  | +            assert(!ZSTD_isError(oneSeqSize));
 | 
	
		
			
				|  |  | +            if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |              if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
 | 
	
		
			
				|  |  |              PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */
 | 
	
		
			
				|  |  |              sequences[seqNb & STORED_SEQS_MASK] = sequence;
 | 
	
		
			
				|  |  |              op += oneSeqSize;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        RETURN_ERROR_IF(seqNb<nbSeq, corruption_detected);
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(seqNb<nbSeq, corruption_detected, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /* finish queue */
 | 
	
		
			
				|  |  |          seqNb -= seqAdvance;
 | 
	
		
			
				|  |  |          for ( ; seqNb<nbSeq ; seqNb++) {
 | 
	
		
			
				|  |  |              size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd);
 | 
	
		
			
				|  |  | +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE)
 | 
	
		
			
				|  |  | +            assert(!ZSTD_isError(oneSeqSize));
 | 
	
		
			
				|  |  | +            if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |              if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
 | 
	
		
			
				|  |  |              op += oneSeqSize;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -1118,9 +1207,11 @@ 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;
 | 
	
		
			
				|  |  | +        RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
 | 
	
		
			
				|  |  | +        if (op != NULL) {
 | 
	
		
			
				|  |  | +            memcpy(op, litPtr, lastLLSize);
 | 
	
		
			
				|  |  | +            op += lastLLSize;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return op-ostart;
 | 
	
	
		
			
				|  | @@ -1130,9 +1221,10 @@ static size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                   void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                             const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                           const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                           const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                           const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +    return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1146,9 +1238,10 @@ DONT_VECTORIZE
 | 
	
		
			
				|  |  |  ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                   void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                             const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                           const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                           const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                           const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +    return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1157,9 +1250,10 @@ static TARGET_ATTRIBUTE("bmi2") size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                   void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                             const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                           const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                           const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                           const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +    return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1169,21 +1263,23 @@ typedef size_t (*ZSTD_decompressSequences_t)(
 | 
	
		
			
				|  |  |                              ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                              void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                              const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                            const ZSTD_longOffset_e isLongOffset);
 | 
	
		
			
				|  |  | +                            const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                            const int frame);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
 | 
	
		
			
				|  |  |  static size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                     const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                   const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                   const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                   const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      DEBUGLOG(5, "ZSTD_decompressSequences");
 | 
	
		
			
				|  |  |  #if DYNAMIC_BMI2
 | 
	
		
			
				|  |  |      if (dctx->bmi2) {
 | 
	
		
			
				|  |  | -        return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +        return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | -  return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +  return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1198,15 +1294,16 @@ static size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                               void* dst, size_t maxDstSize,
 | 
	
		
			
				|  |  |                               const void* seqStart, size_t seqSize, int nbSeq,
 | 
	
		
			
				|  |  | -                             const ZSTD_longOffset_e isLongOffset)
 | 
	
		
			
				|  |  | +                             const ZSTD_longOffset_e isLongOffset,
 | 
	
		
			
				|  |  | +                             const int frame)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      DEBUGLOG(5, "ZSTD_decompressSequencesLong");
 | 
	
		
			
				|  |  |  #if DYNAMIC_BMI2
 | 
	
		
			
				|  |  |      if (dctx->bmi2) {
 | 
	
		
			
				|  |  | -        return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +        return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | -  return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +  return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1240,7 +1337,6 @@ ZSTD_getLongOffsetsShare(const ZSTD_seqSymbol* offTable)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  size_t
 | 
	
		
			
				|  |  |  ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                                void* dst, size_t dstCapacity,
 | 
	
	
		
			
				|  | @@ -1256,7 +1352,7 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |      ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN))));
 | 
	
		
			
				|  |  |      DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong);
 | 
	
		
			
				|  |  | +    RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* Decode literals section */
 | 
	
		
			
				|  |  |      {   size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
 | 
	
	
		
			
				|  | @@ -1282,6 +1378,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
 | 
	
	
		
			
				|  | @@ -1300,17 +1398,28 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |          if (usePrefetchDecoder)
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT
 | 
	
		
			
				|  |  | -            return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +            return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG
 | 
	
		
			
				|  |  |          /* else */
 | 
	
		
			
				|  |  | -        return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset);
 | 
	
		
			
				|  |  | +        return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (dst != dctx->previousDstEnd) {   /* not contiguous */
 | 
	
		
			
				|  |  | +        dctx->dictEnd = dctx->previousDstEnd;
 | 
	
		
			
				|  |  | +        dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
 | 
	
		
			
				|  |  | +        dctx->prefixStart = dst;
 | 
	
		
			
				|  |  | +        dctx->previousDstEnd = dst;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
 | 
	
		
			
				|  |  |                              void* dst, size_t dstCapacity,
 | 
	
		
			
				|  |  |                        const void* src, size_t srcSize)
 |