mirror of
https://github.com/facebook/zstd.git
synced 2025-07-30 22:23:13 +03:00
Fixed : bug in compression in specific conditions (too small dst size)
This commit is contained in:
@ -2044,6 +2044,7 @@ size_t HUF_compress_usingCTable(void* dst, size_t dstSize, const void* src, size
|
|||||||
FSE_CStream_t bitC;
|
FSE_CStream_t bitC;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
|
if (dstSize < 8) return 0; /* need a minimum for jumpTable and first symbols */
|
||||||
op += 6; /* jump Table -- could be optimized by delta / deviation */
|
op += 6; /* jump Table -- could be optimized by delta / deviation */
|
||||||
errorCode = FSE_initCStream(&bitC, op, oend-op);
|
errorCode = FSE_initCStream(&bitC, op, oend-op);
|
||||||
if (FSE_isError(errorCode)) return 0;
|
if (FSE_isError(errorCode)) return 0;
|
||||||
|
59
lib/zstd.c
59
lib/zstd.c
@ -322,6 +322,11 @@ ZSTD_Cctx* ZSTD_createCCtx(void)
|
|||||||
ZSTD_Cctx* ctx = (ZSTD_Cctx*) malloc( sizeof(ZSTD_Cctx) );
|
ZSTD_Cctx* ctx = (ZSTD_Cctx*) malloc( sizeof(ZSTD_Cctx) );
|
||||||
if (ctx==NULL) return NULL;
|
if (ctx==NULL) return NULL;
|
||||||
ctx->seqStore.buffer = malloc(WORKPLACESIZE);
|
ctx->seqStore.buffer = malloc(WORKPLACESIZE);
|
||||||
|
if (ctx->seqStore.buffer==NULL)
|
||||||
|
{
|
||||||
|
free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ctx->seqStore.offsetStart = (U32*) (ctx->seqStore.buffer);
|
ctx->seqStore.offsetStart = (U32*) (ctx->seqStore.buffer);
|
||||||
ctx->seqStore.offCodeStart = (BYTE*) (ctx->seqStore.offsetStart + (BLOCKSIZE>>2));
|
ctx->seqStore.offCodeStart = (BYTE*) (ctx->seqStore.offsetStart + (BLOCKSIZE>>2));
|
||||||
ctx->seqStore.litStart = ctx->seqStore.offCodeStart + (BLOCKSIZE>>2);
|
ctx->seqStore.litStart = ctx->seqStore.offCodeStart + (BLOCKSIZE>>2);
|
||||||
@ -1120,6 +1125,7 @@ size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSi
|
|||||||
size_t r;
|
size_t r;
|
||||||
|
|
||||||
ctx = ZSTD_createCCtx();
|
ctx = ZSTD_createCCtx();
|
||||||
|
if (ctx==NULL) return (size_t)-ZSTD_ERROR_GENERIC;
|
||||||
r = ZSTD_compressCCtx(ctx, dst, maxDstSize, src, srcSize);
|
r = ZSTD_compressCCtx(ctx, dst, maxDstSize, src, srcSize);
|
||||||
ZSTD_freeCCtx(ctx);
|
ZSTD_freeCCtx(ctx);
|
||||||
return r;
|
return r;
|
||||||
@ -1171,6 +1177,7 @@ static size_t ZSTD_decompressLiterals(void* ctx,
|
|||||||
op = oend - litSize;
|
op = oend - litSize;
|
||||||
|
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
|
if (litSize > maxDstSize) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall;
|
||||||
errorCode = HUF_decompress(op, litSize, ip+2, srcSize-2);
|
errorCode = HUF_decompress(op, litSize, ip+2, srcSize-2);
|
||||||
if (FSE_isError(errorCode)) return (size_t)-ZSTD_ERROR_GENERIC;
|
if (FSE_isError(errorCode)) return (size_t)-ZSTD_ERROR_GENERIC;
|
||||||
return litSize;
|
return litSize;
|
||||||
@ -1195,10 +1202,15 @@ size_t ZSTD_decodeLiteralsBlock(void* ctx,
|
|||||||
|
|
||||||
switch(litbp.blockType)
|
switch(litbp.blockType)
|
||||||
{
|
{
|
||||||
case bt_raw: *litStart = ip; ip += litcSize; *litSize = litcSize; break;
|
case bt_raw:
|
||||||
|
*litStart = ip;
|
||||||
|
ip += litcSize;
|
||||||
|
*litSize = litcSize;
|
||||||
|
break;
|
||||||
case bt_rle:
|
case bt_rle:
|
||||||
{
|
{
|
||||||
size_t rleSize = litbp.origSize;
|
size_t rleSize = litbp.origSize;
|
||||||
|
if (rleSize>maxDstSize) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall;
|
||||||
memset(oend - rleSize, *ip, rleSize);
|
memset(oend - rleSize, *ip, rleSize);
|
||||||
*litStart = oend - rleSize;
|
*litStart = oend - rleSize;
|
||||||
*litSize = rleSize;
|
*litSize = rleSize;
|
||||||
@ -1326,13 +1338,12 @@ typedef struct {
|
|||||||
FSE_DState_t stateLL;
|
FSE_DState_t stateLL;
|
||||||
FSE_DState_t stateOffb;
|
FSE_DState_t stateOffb;
|
||||||
FSE_DState_t stateML;
|
FSE_DState_t stateML;
|
||||||
seq_t seq;
|
|
||||||
size_t prevOffset;
|
size_t prevOffset;
|
||||||
const BYTE* dumps;
|
const BYTE* dumps;
|
||||||
} seqState_t;
|
} seqState_t;
|
||||||
|
|
||||||
|
|
||||||
static void ZSTD_decodeSequence(seqState_t* seqState)
|
static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState)
|
||||||
{
|
{
|
||||||
size_t litLength;
|
size_t litLength;
|
||||||
size_t prevOffset;
|
size_t prevOffset;
|
||||||
@ -1342,8 +1353,8 @@ static void ZSTD_decodeSequence(seqState_t* seqState)
|
|||||||
|
|
||||||
/* Literal length */
|
/* Literal length */
|
||||||
litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream));
|
litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream));
|
||||||
prevOffset = litLength ? seqState->seq.offset : seqState->prevOffset;
|
prevOffset = litLength ? seq->offset : seqState->prevOffset;
|
||||||
seqState->prevOffset = seqState->seq.offset;
|
seqState->prevOffset = seq->offset;
|
||||||
if (litLength == MaxLL)
|
if (litLength == MaxLL)
|
||||||
{
|
{
|
||||||
U32 add = *dumps++;
|
U32 add = *dumps++;
|
||||||
@ -1382,9 +1393,9 @@ static void ZSTD_decodeSequence(seqState_t* seqState)
|
|||||||
matchLength += MINMATCH;
|
matchLength += MINMATCH;
|
||||||
|
|
||||||
/* save result */
|
/* save result */
|
||||||
seqState->seq.litLength = litLength;
|
seq->litLength = litLength;
|
||||||
seqState->seq.offset = offset;
|
seq->offset = offset;
|
||||||
seqState->seq.matchLength = matchLength;
|
seq->matchLength = matchLength;
|
||||||
seqState->dumps = dumps;
|
seqState->dumps = dumps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1394,20 +1405,24 @@ static size_t ZSTD_execSequence(BYTE* op, seq_t sequence, const BYTE** litPtr, B
|
|||||||
static const int dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; /* added */
|
static const int dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; /* added */
|
||||||
static const int dec64table[] = {8, 8, 8, 7, 8, 9,10,11}; /* substracted */
|
static const int dec64table[] = {8, 8, 8, 7, 8, 9,10,11}; /* substracted */
|
||||||
const BYTE* const ostart = op;
|
const BYTE* const ostart = op;
|
||||||
|
size_t litLength = sequence.litLength;
|
||||||
|
BYTE* const endMatch = op + litLength + sequence.matchLength; /* risk : address space overflow (32-bits) */
|
||||||
|
const BYTE* const litEnd = *litPtr + litLength;
|
||||||
|
|
||||||
|
/* check */
|
||||||
|
if (endMatch > oend) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall;
|
||||||
|
|
||||||
/* copy Literals */
|
/* copy Literals */
|
||||||
const BYTE* const litEnd = *litPtr + sequence.litLength; /* possible overflow at op + litLength ? */
|
if (((size_t)(*litPtr - op) < 8) || ((size_t)(oend-litEnd) < 8) || (op+litLength > oend-8))
|
||||||
if (((size_t)(*litPtr - op) < 8) || ((size_t)(oend-litEnd) < 8))
|
memmove(op, *litPtr, litLength); /* overwrite risk */
|
||||||
memmove(op, *litPtr, sequence.litLength); /* overwrite risk */
|
|
||||||
else
|
else
|
||||||
ZSTD_wildcopy(op, *litPtr, sequence.litLength);
|
ZSTD_wildcopy(op, *litPtr, litLength);
|
||||||
op += sequence.litLength;
|
op += litLength;
|
||||||
*litPtr = litEnd;
|
*litPtr = litEnd;
|
||||||
|
|
||||||
/* copy Match */
|
/* copy Match */
|
||||||
{
|
{
|
||||||
const BYTE* match = op - sequence.offset; /* possible underflow at op - offset ? */
|
const BYTE* match = op - sequence.offset; /* possible underflow at op - offset ? */
|
||||||
BYTE* const endMatch = op + sequence.matchLength; /* possible overflow at op + matchLength ? */
|
|
||||||
size_t qutt=12;
|
size_t qutt=12;
|
||||||
U64 saved[2];
|
U64 saved[2];
|
||||||
const U32 overlapRisk = (((size_t)(litEnd - endMatch)) < 12);
|
const U32 overlapRisk = (((size_t)(litEnd - endMatch)) < 12);
|
||||||
@ -1483,9 +1498,10 @@ static size_t ZSTD_decompressSequences(
|
|||||||
|
|
||||||
/* Regen sequences */
|
/* Regen sequences */
|
||||||
{
|
{
|
||||||
|
seq_t sequence;
|
||||||
seqState_t seqState;
|
seqState_t seqState;
|
||||||
|
|
||||||
memset(&seqState, 0, sizeof(seqState));
|
memset(&sequence, 0, sizeof(sequence));
|
||||||
seqState.dumps = dumps;
|
seqState.dumps = dumps;
|
||||||
FSE_initDStream(&(seqState.DStream), ip, iend-ip);
|
FSE_initDStream(&(seqState.DStream), ip, iend-ip);
|
||||||
FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL);
|
FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL);
|
||||||
@ -1494,9 +1510,12 @@ static size_t ZSTD_decompressSequences(
|
|||||||
|
|
||||||
for ( ; (FSE_reloadDStream(&(seqState.DStream)) < FSE_DStream_completed) || (nbSeq>0) ; )
|
for ( ; (FSE_reloadDStream(&(seqState.DStream)) < FSE_DStream_completed) || (nbSeq>0) ; )
|
||||||
{
|
{
|
||||||
|
size_t oneSeqSize;
|
||||||
nbSeq--;
|
nbSeq--;
|
||||||
ZSTD_decodeSequence(&seqState);
|
ZSTD_decodeSequence(&sequence, &seqState);
|
||||||
op += ZSTD_execSequence(op, seqState.seq, &litPtr, oend);
|
oneSeqSize = ZSTD_execSequence(op, sequence, &litPtr, oend);
|
||||||
|
if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
|
||||||
|
op += oneSeqSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if reached exact end */
|
/* check if reached exact end */
|
||||||
@ -1506,6 +1525,7 @@ static size_t ZSTD_decompressSequences(
|
|||||||
/* last literal segment */
|
/* last literal segment */
|
||||||
{
|
{
|
||||||
size_t lastLLSize = litEnd - litPtr;
|
size_t lastLLSize = litEnd - litPtr;
|
||||||
|
if (op+lastLLSize > oend) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall;
|
||||||
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
if (op != litPtr) memmove(op, litPtr, lastLLSize);
|
||||||
op += lastLLSize;
|
op += lastLLSize;
|
||||||
}
|
}
|
||||||
@ -1718,7 +1738,7 @@ static size_t ZSTD_decompressDCtx(void* ctx, void* dst, size_t maxDstSize, const
|
|||||||
blockProperties_t blockProperties;
|
blockProperties_t blockProperties;
|
||||||
|
|
||||||
/* Frame Header */
|
/* Frame Header */
|
||||||
if (srcSize < ZSTD_frameHeaderSize) return (size_t)-ZSTD_ERROR_SrcSize;
|
if (srcSize < ZSTD_frameHeaderSize+ZSTD_blockHeaderSize) return (size_t)-ZSTD_ERROR_SrcSize;
|
||||||
magicNumber = ZSTD_readBE32(src);
|
magicNumber = ZSTD_readBE32(src);
|
||||||
if (magicNumber != ZSTD_magicNumber) return (size_t)-ZSTD_ERROR_MagicNumber;
|
if (magicNumber != ZSTD_magicNumber) return (size_t)-ZSTD_ERROR_MagicNumber;
|
||||||
ip += ZSTD_frameHeaderSize; remainingSize -= ZSTD_frameHeaderSize;
|
ip += ZSTD_frameHeaderSize; remainingSize -= ZSTD_frameHeaderSize;
|
||||||
@ -1727,8 +1747,7 @@ static size_t ZSTD_decompressDCtx(void* ctx, void* dst, size_t maxDstSize, const
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
size_t blockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties);
|
size_t blockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties);
|
||||||
if (ZSTD_isError(blockSize))
|
if (ZSTD_isError(blockSize)) return blockSize;
|
||||||
return blockSize;
|
|
||||||
|
|
||||||
ip += ZSTD_blockHeaderSize;
|
ip += ZSTD_blockHeaderSize;
|
||||||
remainingSize -= ZSTD_blockHeaderSize;
|
remainingSize -= ZSTD_blockHeaderSize;
|
||||||
|
@ -359,15 +359,18 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit
|
|||||||
CHECK(ZSTD_isError(cSize), "ZSTD_compress failed");
|
CHECK(ZSTD_isError(cSize), "ZSTD_compress failed");
|
||||||
|
|
||||||
/* compression failure test : too small dest buffer */
|
/* compression failure test : too small dest buffer */
|
||||||
|
if (cSize > 3)
|
||||||
{
|
{
|
||||||
size_t errorCode;
|
size_t errorCode;
|
||||||
const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
|
const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
|
||||||
const size_t tooSmallSize = cSize - missing;
|
const size_t tooSmallSize = cSize - missing;
|
||||||
void* dBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */
|
static const U32 endMark = 0x4DC2B1A9;
|
||||||
CHECK(dBufferTooSmall == NULL, "not enough memory !");
|
U32 endCheck;
|
||||||
errorCode = ZSTD_compress(dBufferTooSmall, tooSmallSize, srcBuffer + sampleStart, sampleSize);
|
memcpy(dstBuffer+tooSmallSize, &endMark, 4);
|
||||||
|
errorCode = ZSTD_compress(dstBuffer, tooSmallSize, srcBuffer + sampleStart, sampleSize);
|
||||||
CHECK(!ZSTD_isError(errorCode), "ZSTD_compress should have failed ! (buffer too small)");
|
CHECK(!ZSTD_isError(errorCode), "ZSTD_compress should have failed ! (buffer too small)");
|
||||||
free(dBufferTooSmall);
|
memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
|
||||||
|
CHECK(endCheck != endMark, "ZSTD_compress : dst buffer overflow");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* successfull decompression tests*/
|
/* successfull decompression tests*/
|
||||||
|
Reference in New Issue
Block a user