diff options
author | Yann Collet <Cyan4973@users.noreply.github.com> | 2020-10-02 08:30:25 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-02 08:30:25 -0700 |
commit | d1414fd5524a70d47656e0fceb58ee10dc573b75 (patch) | |
tree | 42cf5090fffe73fd84e3ef22303ee9da860dc879 | |
parent | 0aed7314de48c90b8aeed8df16bad38b585f19fe (diff) | |
parent | 056cdd6cc67fbce0f83c59e30dd6a1196d59727f (diff) | |
download | lz4-d1414fd5524a70d47656e0fceb58ee10dc573b75.tar.gz lz4-d1414fd5524a70d47656e0fceb58ee10dc573b75.tar.bz2 lz4-d1414fd5524a70d47656e0fceb58ee10dc573b75.zip |
Merge pull request #925 from lz4/test_null
add LZ4F_decompress() tests with (NULL,0) input and output
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | lib/lz4frame.c | 84 | ||||
-rw-r--r-- | tests/frametest.c | 11 |
3 files changed, 62 insertions, 37 deletions
@@ -151,9 +151,11 @@ usan: clean usan32: clean CFLAGS="-m32 -O3 -g -fsanitize=undefined" $(MAKE) test FUZZER_TIME="-T30s" NB_LOOPS=-i1 +SCANBUILD ?= scan-build +SCANBUILD_FLAGS += --status-bugs -v --force-analyze-debug-code .PHONY: staticAnalyze staticAnalyze: clean - CPPFLAGS=-DLZ4_DEBUG=1 CFLAGS=-g scan-build --status-bugs -v --force-analyze-debug-code $(MAKE) all V=1 DEBUGLEVEL=1 + CPPFLAGS=-DLZ4_DEBUG=1 CFLAGS=-g $(SCANBUILD) $(SCANBUILD_FLAGS) $(MAKE) all V=1 DEBUGLEVEL=1 .PHONY: cppcheck cppcheck: diff --git a/lib/lz4frame.c b/lib/lz4frame.c index bfdef5d..2976bb1 100644 --- a/lib/lz4frame.c +++ b/lib/lz4frame.c @@ -991,6 +991,7 @@ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, BYTE* dstPtr = dstStart; size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); + DEBUGLOG(5,"LZ4F_compressEnd: dstCapacity=%u", (unsigned)dstCapacity); if (LZ4F_isError(flushSize)) return flushSize; dstPtr += flushSize; @@ -1004,6 +1005,7 @@ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) { U32 const xxh = XXH32_digest(&(cctxPtr->xxh)); if (dstCapacity < 8) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); + DEBUGLOG(5,"Writing 32-bit content checksum"); LZ4F_writeLE32(dstPtr, xxh); dstPtr+=4; /* content Checksum */ } @@ -1114,6 +1116,7 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize size_t frameHeaderSize; const BYTE* srcPtr = (const BYTE*)src; + DEBUGLOG(5, "LZ4F_decodeHeader"); /* need to decode header to get frameInfo */ if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */ MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo)); @@ -1134,8 +1137,10 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize /* control magic number */ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) + if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) { + DEBUGLOG(4, "frame header error : unknown magic number"); return err0r(LZ4F_ERROR_frameType_unknown); + } #endif dctx->frameInfo.frameType = LZ4F_frame; @@ -1393,6 +1398,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, size_t nextSrcSizeHint = 1; + DEBUGLOG(5, "LZ4F_decompress : %p,%u => %p,%u", + srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr); if (dstBuffer == NULL) assert(*dstSizePtr == 0); MEM_INIT(&optionsNull, 0, sizeof(optionsNull)); if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull; @@ -1407,6 +1414,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, { case dstage_getFrameHeader: + DEBUGLOG(6, "dstage_getFrameHeader"); if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */ size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, (size_t)(srcEnd-srcPtr)); /* will update dStage appropriately */ if (LZ4F_isError(hSize)) return hSize; @@ -1420,6 +1428,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, /* fall-through */ case dstage_storeFrameHeader: + DEBUGLOG(6, "dstage_storeFrameHeader"); { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr)); memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); dctx->tmpInSize += sizeToCopy; @@ -1436,6 +1445,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, break; case dstage_init: + DEBUGLOG(6, "dstage_init"); if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_reset(&(dctx->xxh), 0); /* internal buffers allocation */ { size_t const bufferNeeded = dctx->maxBlockSize @@ -1521,22 +1531,26 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, } case dstage_copyDirect: /* uncompressed block */ - if (dstPtr==NULL) { doAnotherStage = 0; break; } - { size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr)); - size_t const sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize); - memcpy(dstPtr, srcPtr, sizeToCopy); - if (dctx->frameInfo.blockChecksumFlag) { - (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy); - } - if (dctx->frameInfo.contentChecksumFlag) - (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy); - if (dctx->frameInfo.contentSize) - dctx->frameRemainingSize -= sizeToCopy; + DEBUGLOG(6, "dstage_copyDirect"); + { size_t sizeToCopy; + if (dstPtr == NULL) { + sizeToCopy = 0; + } else { + size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr)); + sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize); + memcpy(dstPtr, srcPtr, sizeToCopy); + if (dctx->frameInfo.blockChecksumFlag) { + (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy); + } + if (dctx->frameInfo.contentChecksumFlag) + (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy); + if (dctx->frameInfo.contentSize) + dctx->frameRemainingSize -= sizeToCopy; - /* history management (linked blocks only)*/ - if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { - LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0); - } + /* history management (linked blocks only)*/ + if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { + LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0); + } } srcPtr += sizeToCopy; dstPtr += sizeToCopy; @@ -1549,15 +1563,16 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, break; } dctx->tmpInTarget -= sizeToCopy; /* need to copy more */ - nextSrcSizeHint = dctx->tmpInTarget + - +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0) - + BHSize /* next header size */; - doAnotherStage = 0; - break; } + nextSrcSizeHint = dctx->tmpInTarget + + +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0) + + BHSize /* next header size */; + doAnotherStage = 0; + break; /* check block checksum for recently transferred uncompressed block */ case dstage_getBlockChecksum: + DEBUGLOG(6, "dstage_getBlockChecksum"); { const void* crcSrc; if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) { crcSrc = srcPtr; @@ -1577,8 +1592,12 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, { U32 const readCRC = LZ4F_readLE32(crcSrc); U32 const calcCRC = XXH32_digest(&dctx->blockChecksum); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (readCRC != calcCRC) + DEBUGLOG(6, "compare block checksum"); + if (readCRC != calcCRC) { + DEBUGLOG(4, "incorrect block checksum: %08X != %08X", + readCRC, calcCRC); return err0r(LZ4F_ERROR_blockChecksum_invalid); + } #else (void)readCRC; (void)calcCRC; @@ -1588,6 +1607,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, break; case dstage_getCBlock: + DEBUGLOG(6, "dstage_getCBlock"); if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) { dctx->tmpInSize = 0; dctx->dStage = dstage_storeCBlock; @@ -1701,8 +1721,9 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, /* fall-through */ case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */ - if (dstPtr == NULL) { doAnotherStage = 0; nextSrcSizeHint = BHSize; break; } - { size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr)); + DEBUGLOG(6, "dstage_flushOut"); + if (dstPtr != NULL) { + size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr)); memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy); /* dictionary management */ @@ -1711,16 +1732,15 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx, dctx->tmpOutStart += sizeToCopy; dstPtr += sizeToCopy; - - if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */ - dctx->dStage = dstage_getBlockHeader; /* get next block */ - break; - } - /* could not flush everything : stop there, just request a block header */ - doAnotherStage = 0; - nextSrcSizeHint = BHSize; + } + if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */ + dctx->dStage = dstage_getBlockHeader; /* get next block */ break; } + /* could not flush everything : stop there, just request a block header */ + doAnotherStage = 0; + nextSrcSizeHint = BHSize; + break; case dstage_getSuffix: if (dctx->frameRemainingSize) diff --git a/tests/frametest.c b/tests/frametest.c index 3a0f64f..2633c90 100644 --- a/tests/frametest.c +++ b/tests/frametest.c @@ -839,26 +839,29 @@ size_t test_lz4f_decompression_wBuffers( size_t iSize = iSizeMax; size_t const oSizeCand = (FUZ_rand(randState) & ((1<<nbBitsO)-1)) + 2; size_t const oSizeMax = MIN(oSizeCand, (size_t)(oend-op)); + int const sentinelTest = (op + oSizeMax < oend); size_t oSize = oSizeMax; BYTE const mark = (BYTE)(FUZ_rand(randState) & 255); LZ4F_decompressOptions_t dOptions; memset(&dOptions, 0, sizeof(dOptions)); dOptions.stableDst = FUZ_rand(randState) & 1; if (o_scenario == o_overwrite) dOptions.stableDst = 0; /* overwrite mode */ - if (op + oSizeMax < oend) op[oSizeMax] = mark; + if (sentinelTest) op[oSizeMax] = mark; DISPLAYLEVEL(7, "dstCapacity=%u, presentedInput=%u \n", (unsigned)oSize, (unsigned)iSize); /* read data from byte-exact buffer to catch out-of-bound reads */ { void* const iBuffer = malloc(iSizeMax); + void* const tmpop = (FUZ_rand(randState) & (oSize == 0)) ? NULL : op; + const void* const tmpip = (FUZ_rand(randState) & (iSize == 0)) ? NULL : iBuffer; assert(iBuffer != NULL); memcpy(iBuffer, ip, iSizeMax); - moreToFlush = LZ4F_decompress(dCtx, op, &oSize, iBuffer, &iSize, &dOptions); + moreToFlush = LZ4F_decompress(dCtx, tmpop, &oSize, tmpip, &iSize, &dOptions); free(iBuffer); } DISPLAYLEVEL(7, "oSize=%u, readSize=%u \n", (unsigned)oSize, (unsigned)iSize); - if (op + oSizeMax < oend) { + if (sentinelTest) { CHECK(op[oSizeMax] != mark, "op[oSizeMax] = %02X != %02X : " "Decompression overwrites beyond assigned dst size", op[oSizeMax], mark); @@ -1035,7 +1038,7 @@ int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressi op += 4; if ((prefsPtr!= NULL) && prefsPtr->frameInfo.blockChecksumFlag) { U32 const bc32 = XXH32(op, 0, 0); - op[0] = (BYTE)bc32; /* little endian format */ + op[0] = (BYTE)bc32; /* little endian format */ op[1] = (BYTE)(bc32>>8); op[2] = (BYTE)(bc32>>16); op[3] = (BYTE)(bc32>>24); |