diff options
author | Yann Collet <yann.collet.73@gmail.com> | 2016-08-11 12:44:53 (GMT) |
---|---|---|
committer | Yann Collet <yann.collet.73@gmail.com> | 2016-08-11 12:55:39 (GMT) |
commit | 2ac9ecec685f720876aa2e12277b06f53de03682 (patch) | |
tree | f84d2d47b2ff292bc084a5b531ebc8010819b345 /lib | |
parent | 45ea27949c11afe9df0d7fd274dda8f42748d5a7 (diff) | |
download | lz4-2ac9ecec685f720876aa2e12277b06f53de03682.zip lz4-2ac9ecec685f720876aa2e12277b06f53de03682.tar.gz lz4-2ac9ecec685f720876aa2e12277b06f53de03682.tar.bz2 |
Fixed #157 : LZ4F_getFrameInfo() fails on valid null-content frame
Diffstat (limited to 'lib')
-rw-r--r-- | lib/lz4frame.c | 234 | ||||
-rw-r--r-- | lib/lz4frame.h | 10 |
2 files changed, 134 insertions, 110 deletions
diff --git a/lib/lz4frame.c b/lib/lz4frame.c index 27b86b4..2e42dcc 100644 --- a/lib/lz4frame.c +++ b/lib/lz4frame.c @@ -69,21 +69,65 @@ You can contact the author at : /*-************************************ * Basic Types **************************************/ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ +#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include <stdint.h> -typedef uint8_t BYTE; -typedef uint16_t U16; -typedef uint32_t U32; -typedef int32_t S32; -typedef uint64_t U64; + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; #else -typedef unsigned char BYTE; -typedef unsigned short U16; -typedef unsigned int U32; -typedef signed int S32; -typedef unsigned long long U64; + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; #endif +/* unoptimized version; solves endianess & alignment issues */ +static U32 LZ4F_readLE32 (const void* src) +{ + const BYTE* const srcPtr = (const BYTE*)src; + U32 value32 = srcPtr[0]; + value32 += (srcPtr[1]<<8); + value32 += (srcPtr[2]<<16); + value32 += ((U32)srcPtr[3])<<24; + return value32; +} + +static void LZ4F_writeLE32 (BYTE* dstPtr, U32 value32) +{ + dstPtr[0] = (BYTE)value32; + dstPtr[1] = (BYTE)(value32 >> 8); + dstPtr[2] = (BYTE)(value32 >> 16); + dstPtr[3] = (BYTE)(value32 >> 24); +} + +static U64 LZ4F_readLE64 (const BYTE* srcPtr) +{ + U64 value64 = srcPtr[0]; + value64 += ((U64)srcPtr[1]<<8); + value64 += ((U64)srcPtr[2]<<16); + value64 += ((U64)srcPtr[3]<<24); + value64 += ((U64)srcPtr[4]<<32); + value64 += ((U64)srcPtr[5]<<40); + value64 += ((U64)srcPtr[6]<<48); + value64 += ((U64)srcPtr[7]<<56); + return value64; +} + +static void LZ4F_writeLE64 (BYTE* dstPtr, U64 value64) +{ + dstPtr[0] = (BYTE)value64; + dstPtr[1] = (BYTE)(value64 >> 8); + dstPtr[2] = (BYTE)(value64 >> 16); + dstPtr[3] = (BYTE)(value64 >> 24); + dstPtr[4] = (BYTE)(value64 >> 32); + dstPtr[5] = (BYTE)(value64 >> 40); + dstPtr[6] = (BYTE)(value64 >> 48); + dstPtr[7] = (BYTE)(value64 >> 56); +} + /*-************************************ * Constants @@ -185,50 +229,6 @@ static size_t LZ4F_getBlockSize(unsigned blockSizeID) } -/* unoptimized version; solves endianess & alignment issues */ -static U32 LZ4F_readLE32 (const BYTE* srcPtr) -{ - U32 value32 = srcPtr[0]; - value32 += (srcPtr[1]<<8); - value32 += (srcPtr[2]<<16); - value32 += ((U32)srcPtr[3])<<24; - return value32; -} - -static void LZ4F_writeLE32 (BYTE* dstPtr, U32 value32) -{ - dstPtr[0] = (BYTE)value32; - dstPtr[1] = (BYTE)(value32 >> 8); - dstPtr[2] = (BYTE)(value32 >> 16); - dstPtr[3] = (BYTE)(value32 >> 24); -} - -static U64 LZ4F_readLE64 (const BYTE* srcPtr) -{ - U64 value64 = srcPtr[0]; - value64 += ((U64)srcPtr[1]<<8); - value64 += ((U64)srcPtr[2]<<16); - value64 += ((U64)srcPtr[3]<<24); - value64 += ((U64)srcPtr[4]<<32); - value64 += ((U64)srcPtr[5]<<40); - value64 += ((U64)srcPtr[6]<<48); - value64 += ((U64)srcPtr[7]<<56); - return value64; -} - -static void LZ4F_writeLE64 (BYTE* dstPtr, U64 value64) -{ - dstPtr[0] = (BYTE)value64; - dstPtr[1] = (BYTE)(value64 >> 8); - dstPtr[2] = (BYTE)(value64 >> 16); - dstPtr[3] = (BYTE)(value64 >> 24); - dstPtr[4] = (BYTE)(value64 >> 32); - dstPtr[5] = (BYTE)(value64 >> 40); - dstPtr[6] = (BYTE)(value64 >> 48); - dstPtr[7] = (BYTE)(value64 >> 56); -} - - static BYTE LZ4F_headerChecksum (const void* header, size_t length) { U32 xxh = XXH32(header, length, 0); @@ -722,24 +722,21 @@ size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstB } -/*-******************************* -* Decompression functions -**********************************/ +/*-*************************************************** +* Frame Decompression +*****************************************************/ /* Resource management */ -/* LZ4F_createDecompressionContext() : -* The first thing to do is to create a decompressionContext object, which will be used in all decompression operations. -* This is achieved using LZ4F_createDecompressionContext(). -* The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext object. -* If the result LZ4F_errorCode_t is not zero, there was an error during context creation. -* Object can release its memory using LZ4F_freeDecompressionContext(); +/*! LZ4F_createDecompressionContext() : +* Create a decompressionContext object, which will track all decompression operations. +* Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object. +* Object can later be released using LZ4F_freeDecompressionContext(). +* @return : if != 0, there was an error during context creation. */ LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* LZ4F_decompressionContextPtr, unsigned versionNumber) { - LZ4F_dctx_t* dctxPtr; - - dctxPtr = (LZ4F_dctx_t*)ALLOCATOR(sizeof(LZ4F_dctx_t)); + LZ4F_dctx_t* const dctxPtr = (LZ4F_dctx_t*)ALLOCATOR(sizeof(LZ4F_dctx_t)); if (dctxPtr==NULL) return (LZ4F_errorCode_t)-LZ4F_ERROR_GENERIC; dctxPtr->version = versionNumber; @@ -750,7 +747,7 @@ LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* LZ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t LZ4F_decompressionContext) { LZ4F_errorCode_t result = LZ4F_OK_NoError; - LZ4F_dctx_t* dctxPtr = (LZ4F_dctx_t*)LZ4F_decompressionContext; + LZ4F_dctx_t* const dctxPtr = (LZ4F_dctx_t*)LZ4F_decompressionContext; if (dctxPtr != NULL) { /* can accept NULL input, like free() */ result = (LZ4F_errorCode_t)dctxPtr->dStage; FREEMEM(dctxPtr->tmpIn); @@ -777,12 +774,36 @@ typedef enum { dstage_getHeader=0, dstage_storeHeader, } dStage_t; +/*! LZ4F_headerSize() : +* @return : size of frame header +* or an error code, which can be tested using LZ4F_isError() +*/ +static size_t LZ4F_headerSize(const void* src, size_t srcSize) +{ + /* minimal srcSize to determine header size */ + if (srcSize < 5) return (size_t)-LZ4F_ERROR_frameHeader_incomplete; + + /* special case : skippable frames */ + if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8; + + /* control magic number */ + if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) return (size_t)-LZ4F_ERROR_frameType_unknown; + + /* Frame Header Size */ + { BYTE const FLG = ((const BYTE*)src)[4]; + U32 const contentSizeFlag = (FLG>>3) & _1BIT; + return contentSizeFlag ? maxFHSize : minFHSize; + } +} + + /*! LZ4F_decodeHeader() : - return : nb Bytes read from srcVoidPtr (necessarily <= srcSize) - or an error code (testable with LZ4F_isError()) - output : set internal values of dctx, such as - dctxPtr->frameInfo and dctxPtr->dStage. - input : srcVoidPtr points at the **beginning of the frame** + input : `srcVoidPtr` points at the **beginning of the frame** + output : set internal values of dctx, such as + dctxPtr->frameInfo and dctxPtr->dStage. + Also allocates internal buffers. + @return : nb Bytes read from srcVoidPtr (necessarily <= srcSize) + or an error code (testable with LZ4F_isError()) */ static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, size_t srcSize) { @@ -887,14 +908,14 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, si /*! LZ4F_getFrameInfo() : -* This function decodes frame header information, such as blockSize. -* It is optional : you could start by calling directly LZ4F_decompress() instead. -* The objective is to extract header information without starting decompression, typically for allocation purposes. -* LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t. -* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). -* You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr) -* The function result is an hint of the better srcSize to use for next call to LZ4F_decompress, -* or an error code which can be tested using LZ4F_isError(). +* Decodes frame header information, such as blockSize. +* It is optional : you could start by calling directly LZ4F_decompress() instead. +* The objective is to extract header information without starting decompression, typically for allocation purposes. +* LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t. +* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). +* You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr) +* @return : hint of the better `srcSize` to use for next call to LZ4F_decompress, +* or an error code which can be tested using LZ4F_isError(). */ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t dCtx, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr) @@ -902,16 +923,20 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t dCtx, LZ4F_frameI LZ4F_dctx_t* dctxPtr = (LZ4F_dctx_t*)dCtx; if (dctxPtr->dStage > dstage_storeHeader) { /* note : requires dstage_* header related to be at beginning of enum */ - size_t o=0, i=0; /* frameInfo already decoded */ + size_t o=0, i=0; *srcSizePtr = 0; *frameInfoPtr = dctxPtr->frameInfo; - return LZ4F_decompress(dCtx, NULL, &o, NULL, &i, NULL); + return LZ4F_decompress(dCtx, NULL, &o, NULL, &i, NULL); /* returns : recommended nb of bytes for LZ4F_decompress() */ } else { - size_t o=0; - size_t nextSrcSize = LZ4F_decompress(dCtx, NULL, &o, srcBuffer, srcSizePtr, NULL); - if (dctxPtr->dStage <= dstage_storeHeader) /* note : requires dstage_* header related to be at beginning of enum */ - return (size_t)-LZ4F_ERROR_frameHeader_incomplete; + size_t nextSrcSize, o=0; + size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr); + if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; } + if (*srcSizePtr < hSize) { *srcSizePtr=0; return (size_t)-LZ4F_ERROR_frameHeader_incomplete; } + + *srcSizePtr = hSize; + nextSrcSize = LZ4F_decompress(dCtx, NULL, &o, srcBuffer, srcSizePtr, NULL); + if (dctxPtr->dStage <= dstage_storeHeader) return (size_t)-LZ4F_ERROR_frameHeader_incomplete; /* should not happen, already checked */ *frameInfoPtr = dctxPtr->frameInfo; return nextSrcSize; } @@ -1038,16 +1063,16 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, { case dstage_getHeader: - { if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */ - LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(dctxPtr, srcPtr, srcEnd-srcPtr); - if (LZ4F_isError(errorCode)) return errorCode; - srcPtr += errorCode; - break; - } - dctxPtr->tmpInSize = 0; - dctxPtr->tmpInTarget = minFHSize; /* minimum to attempt decode */ - dctxPtr->dStage = dstage_storeHeader; + if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */ + LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, srcPtr, srcEnd-srcPtr); + if (LZ4F_isError(hSize)) return hSize; + srcPtr += hSize; + break; } + dctxPtr->tmpInSize = 0; + dctxPtr->tmpInTarget = minFHSize; /* minimum to attempt decode */ + dctxPtr->dStage = dstage_storeHeader; + /* pass-through */ case dstage_storeHeader: { size_t sizeToCopy = dctxPtr->tmpInTarget - dctxPtr->tmpInSize; @@ -1060,8 +1085,8 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, doAnotherStage = 0; /* not enough src data, ask for some more */ break; } - { LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget); - if (LZ4F_isError(errorCode)) return errorCode; + { LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget); + if (LZ4F_isError(hSize)) return hSize; } break; } @@ -1076,7 +1101,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, dctxPtr->dStage = dstage_storeCBlockSize; } - if (dctxPtr->dStage == dstage_storeCBlockSize) + if (dctxPtr->dStage == dstage_storeCBlockSize) /* can be skipped */ case dstage_storeCBlockSize: { size_t sizeToCopy = BHSize - dctxPtr->tmpInSize; @@ -1084,7 +1109,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy); srcPtr += sizeToCopy; dctxPtr->tmpInSize += sizeToCopy; - if (dctxPtr->tmpInSize < BHSize) { /* not enough input to get full cBlockSize; wait for more */ + if (dctxPtr->tmpInSize < BHSize) { /* not enough input to get full cBlockSize; wait for more */ nextSrcSizeHint = BHSize - dctxPtr->tmpInSize; doAnotherStage = 0; break; @@ -1093,7 +1118,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, } /* case dstage_decodeCBlockSize: */ /* no more direct access, to prevent scan-build warning */ - { size_t nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU; + { size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU; if (nextCBlockSize==0) { /* frameEnd signal, no more CBlock */ dctxPtr->dStage = dstage_getSuffix; break; @@ -1137,8 +1162,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, } case dstage_getCBlock: /* entry from dstage_decodeCBlockSize */ - if ((size_t)(srcEnd-srcPtr) < dctxPtr->tmpInTarget) - { + if ((size_t)(srcEnd-srcPtr) < dctxPtr->tmpInTarget) { dctxPtr->tmpInSize = 0; dctxPtr->dStage = dstage_storeCBlock; break; @@ -1253,7 +1277,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, } case dstage_getSuffix: - { size_t suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4; + { size_t const suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4; if (dctxPtr->frameRemainingSize) return (size_t)-LZ4F_ERROR_frameSize_wrong; /* incorrect frame size decoded */ if (suffixSize == 0) { /* frame completed */ nextSrcSizeHint = 0; @@ -1270,7 +1294,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, } } - if (dctxPtr->dStage == dstage_storeSuffix) + if (dctxPtr->dStage == dstage_storeSuffix) /* can be skipped */ case dstage_storeSuffix: { size_t sizeToCopy = 4 - dctxPtr->tmpInSize; diff --git a/lib/lz4frame.h b/lib/lz4frame.h index c039e5d..bae4016 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -44,13 +44,13 @@ extern "C" { #endif -/************************************** +/*-************************************ * Includes **************************************/ #include <stddef.h> /* size_t */ -/************************************** +/*-************************************ * Error management **************************************/ typedef size_t LZ4F_errorCode_t; @@ -59,7 +59,7 @@ unsigned LZ4F_isError(LZ4F_errorCode_t code); const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /* return error code string; useful for debugging */ -/************************************** +/*-************************************ * Frame compression types **************************************/ //#define LZ4F_DISABLE_OBSOLETE_ENUMS @@ -125,7 +125,7 @@ typedef struct { } LZ4F_preferences_t; -/*********************************** +/*-********************************* * Simple compression function ***********************************/ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr); @@ -143,7 +143,7 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuf -/********************************** +/*-******************************** * Advanced compression functions **********************************/ typedef struct LZ4F_cctx_s* LZ4F_compressionContext_t; /* must be aligned on 8-bytes */ |