diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 00daa4c70..4091662a9 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2506,11 +2506,11 @@ static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0 */ lastLLSize = seqStoreLiteralsSize - literalsRead; - if (lastLLSize) { + if (lastLLSize > 0) { outSeqs[i].litLength = lastLLSize; outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0; + seqStoreSeqSize++; } - zc->seqCollector.seqIndex += seqStoreSeqSize; } diff --git a/lib/zstd.h b/lib/zstd.h index d2f20be2d..0c243e017 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1115,23 +1115,28 @@ typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params; typedef struct { unsigned int offset; /* The offset of the match. - * If == 0, then represents a section of literals of litLength size + * If offset == 0 and matchLength == 0, + * then this sequence represents last literals in the block of litLength size. */ - unsigned int litLength; /* Literal length */ - unsigned int matchLength; /* Match length. */ + unsigned int litLength; /* Literal length of the sequence. */ + unsigned int matchLength; /* Match length of the sequence. */ + + /* Note: Users of this API may provide a sequence with matchLength == litLength == offset == 0. + * In this case, we will treat the "sequence" as a marker for a block boundary. + */ unsigned int rep; /* Represents which repeat offset is used. Ranges from [0, 3]. * If rep == 0, then this sequence does not contain a repeat offset. - * Otherwise: + * If rep > 0: * If litLength != 0: - * rep == 1 --> offset == repeat offset 1 - * rep == 2 --> offset == repeat offset 2 - * rep == 3 --> offset == repeat offset 3 + * rep == 1 --> offset == repeat_offset_1 + * rep == 2 --> offset == repeat_offset_2 + * rep == 3 --> offset == repeat_offset_3 * If litLength == 0: - * rep == 1 --> offset == repeat offset 2 - * rep == 2 --> offset == repeat offset 3 - * rep == 3 --> offset == repeat offset 1 - 1 + * rep == 1 --> offset == repeat_offset_2 + * rep == 2 --> offset == repeat_offset_3 + * rep == 3 --> offset == repeat_offset_1 - 1 */ } ZSTD_Sequence; diff --git a/tests/fuzzer.c b/tests/fuzzer.c index e54714fdf..038fae1aa 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -310,22 +310,23 @@ static void FUZ_decodeSequences(BYTE* dst, ZSTD_Sequence* seqs, size_t seqsSize, { size_t i; size_t j; - for(i = 0; i < seqsSize - 1; ++i) { - assert(dst + seqs[i].litLength + seqs[i].matchLength < dst + size); - assert(src + seqs[i].litLength + seqs[i].matchLength < src + size); + for(i = 0; i < seqsSize; ++i) { + assert(dst + seqs[i].litLength + seqs[i].matchLength <= dst + size); + assert(src + seqs[i].litLength + seqs[i].matchLength <= src + size); memcpy(dst, src, seqs[i].litLength); dst += seqs[i].litLength; src += seqs[i].litLength; size -= seqs[i].litLength; - for (j = 0; j < seqs[i].matchLength; ++j) - dst[j] = dst[j - seqs[i].offset]; - dst += seqs[i].matchLength; - src += seqs[i].matchLength; - size -= seqs[i].matchLength; + if (seqs[i].offset != 0) { + for (j = 0; j < seqs[i].matchLength; ++j) + dst[j] = dst[j - seqs[i].offset]; + dst += seqs[i].matchLength; + src += seqs[i].matchLength; + size -= seqs[i].matchLength; + } } - memcpy(dst, src, size); } /*============================================= @@ -2666,6 +2667,7 @@ static int basicUnitTests(U32 const seed, double compressibility) ZSTD_freeCCtx(cctx); free(seqs); } + DISPLAYLEVEL(3, "OK \n"); /* Multiple blocks of zeros test */ #define LONGZEROSLENGTH 1000000 /* 1MB of zeros */