1
0
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:
Yann Collet
2015-08-20 07:46:10 +01:00
parent f3cb79b58f
commit 602834f794
3 changed files with 47 additions and 24 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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*/