summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Collet <cyan@fb.com>2017-05-10 23:28:36 (GMT)
committerYann Collet <cyan@fb.com>2017-05-10 23:28:36 (GMT)
commite60cbb5cacaa43eda7a3df7c2d9051a9437e7046 (patch)
tree0c7825e9a62639c15380479e9ca49596e0022e7e
parent2012e4de9e2c33a5abb34d40082afc8918852c6e (diff)
downloadlz4-e60cbb5cacaa43eda7a3df7c2d9051a9437e7046.zip
lz4-e60cbb5cacaa43eda7a3df7c2d9051a9437e7046.tar.gz
lz4-e60cbb5cacaa43eda7a3df7c2d9051a9437e7046.tar.bz2
added test for LZ4F_resetDecompressionContext()
-rw-r--r--doc/lz4frame_manual.html9
-rw-r--r--lib/lz4frame.c66
-rw-r--r--lib/lz4frame.h9
-rw-r--r--lib/lz4frame_static.h9
-rw-r--r--tests/frametest.c45
5 files changed, 79 insertions, 59 deletions
diff --git a/doc/lz4frame_manual.html b/doc/lz4frame_manual.html
index fa2c0b9..87750a1 100644
--- a/doc/lz4frame_manual.html
+++ b/doc/lz4frame_manual.html
@@ -255,14 +255,11 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);
</p></pre><BR>
-<pre><b>LZ4F_errorCode_t LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);
-</b><p> When decompression ends successfully,
- it's possible to start a new decompression immediately
- re-using the same context.
- However, in case of an error, the context is left in "undefined" state.
+<pre><b>void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx); </b>/* always successful */<b>
+</b><p> In case of an error, the context is left in "undefined" state.
In which case, it's necessary to reset it, before re-using it.
This method can also be used to abruptly stop an unfinished decompression,
- and start a new on the same context.
+ and start a new with the same context.
</p></pre><BR>
</html>
diff --git a/lib/lz4frame.c b/lib/lz4frame.c
index 7422638..fb37789 100644
--- a/lib/lz4frame.c
+++ b/lib/lz4frame.c
@@ -798,10 +798,9 @@ typedef enum {
dstage_skipSkippable
} dStage_t;
-LZ4F_errorCode_t LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
+void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
{
dctx->dStage = dstage_getHeader;
- return 0;
}
@@ -939,7 +938,8 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameIn
size_t o=0, i=0;
*srcSizePtr = 0;
*frameInfoPtr = dctxPtr->frameInfo;
- return LZ4F_decompress(dctxPtr, NULL, &o, NULL, &i, NULL); /* returns : recommended nb of bytes for LZ4F_decompress() */
+ /* returns : recommended nb of bytes for LZ4F_decompress() */
+ return LZ4F_decompress(dctxPtr, NULL, &o, NULL, &i, NULL);
} else {
if (dctxPtr->dStage == dstage_storeHeader) {
/* frame decoding already started, in the middle of header => automatic fail */
@@ -949,7 +949,10 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameIn
size_t decodeResult;
size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);
if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }
- if (*srcSizePtr < hSize) { *srcSizePtr=0; return err0r(LZ4F_ERROR_frameHeader_incomplete); }
+ if (*srcSizePtr < hSize) {
+ *srcSizePtr=0;
+ return err0r(LZ4F_ERROR_frameHeader_incomplete);
+ }
decodeResult = LZ4F_decodeHeader(dctxPtr, srcBuffer, hSize);
if (LZ4F_isError(decodeResult)) {
@@ -965,10 +968,15 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameIn
/* trivial redirector, for common prototype */
-static int LZ4F_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize)
+static int LZ4F_decompress_safe (const char* src,
+ char* dst,
+ int compressedSize,
+ int dstCapacity,
+ const char* dictStart,
+ int dictSize)
{
(void)dictStart; (void)dictSize;
- return LZ4_decompress_safe (source, dest, compressedSize, maxDecompressedSize);
+ return LZ4_decompress_safe (src, dst, compressedSize, dstCapacity);
}
@@ -1101,7 +1109,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
doAnotherStage = 0; /* not enough src data, ask for some more */
break;
}
- { LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget);
+ { LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget); /* will change dStage appropriately */
if (LZ4F_isError(hSize)) return hSize;
}
break;
@@ -1149,7 +1157,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
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 for cBlockSize */
nextSrcSizeHint = BHSize - dctxPtr->tmpInSize;
doAnotherStage = 0;
break;
@@ -1157,13 +1165,14 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
selectedIn = dctxPtr->tmpIn;
}
- /* case dstage_decodeCBlockSize: */ /* no more direct access, to prevent scan-build warning */
+ /* case dstage_decodeCBlockSize: */ /* no more direct access, to remove scan-build warning */
{ size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
if (nextCBlockSize==0) { /* frameEnd signal, no more CBlock */
dctxPtr->dStage = dstage_getSuffix;
break;
}
- if (nextCBlockSize > dctxPtr->maxBlockSize) return err0r(LZ4F_ERROR_GENERIC); /* invalid cBlockSize */
+ if (nextCBlockSize > dctxPtr->maxBlockSize)
+ return err0r(LZ4F_ERROR_maxBlockSize_invalid);
dctxPtr->tmpInTarget = nextCBlockSize;
if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
dctxPtr->dStage = dstage_copyDirect;
@@ -1179,11 +1188,13 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
case dstage_copyDirect: /* uncompressed block */
{ size_t sizeToCopy = dctxPtr->tmpInTarget;
- if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr; /* not enough input to read full block */
+ if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr;
if ((size_t)(dstEnd-dstPtr) < sizeToCopy) sizeToCopy = dstEnd - dstPtr;
memcpy(dstPtr, srcPtr, sizeToCopy);
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), srcPtr, sizeToCopy);
- if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= sizeToCopy;
+ if (dctxPtr->frameInfo.contentChecksumFlag)
+ XXH32_update(&(dctxPtr->xxh), srcPtr, sizeToCopy);
+ if (dctxPtr->frameInfo.contentSize)
+ dctxPtr->frameRemainingSize -= sizeToCopy;
/* dictionary management */
if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
@@ -1244,10 +1255,14 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
else
decoder = LZ4F_decompress_safe;
- decodedSize = decoder((const char*)selectedIn, (char*)dstPtr, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
+ decodedSize = decoder((const char*)selectedIn, (char*)dstPtr,
+ (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize,
+ (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
- if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize;
+ if (dctxPtr->frameInfo.contentChecksumFlag)
+ XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
+ if (dctxPtr->frameInfo.contentSize)
+ dctxPtr->frameRemainingSize -= decodedSize;
/* dictionary management */
if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
@@ -1284,10 +1299,15 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
}
/* Decode */
- decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
- if (decodedSize < 0) return err0r(LZ4F_ERROR_decompressionFailed); /* decompression failed */
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
- if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize;
+ decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut,
+ (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize,
+ (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
+ if (decodedSize < 0)
+ return err0r(LZ4F_ERROR_decompressionFailed); /* decompression failed */
+ if (dctxPtr->frameInfo.contentChecksumFlag)
+ XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
+ if (dctxPtr->frameInfo.contentSize)
+ dctxPtr->frameRemainingSize -= decodedSize;
dctxPtr->tmpOutSize = decodedSize;
dctxPtr->tmpOutStart = 0;
dctxPtr->dStage = dstage_flushOut;
@@ -1318,7 +1338,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
case dstage_getSuffix:
{ size_t const suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4;
- if (dctxPtr->frameRemainingSize) return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
+ if (dctxPtr->frameRemainingSize)
+ return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
if (suffixSize == 0) { /* frame completed */
nextSrcSizeHint = 0;
dctxPtr->dStage = dstage_getHeader;
@@ -1379,7 +1400,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
memcpy(dctxPtr->header + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
srcPtr += sizeToCopy;
dctxPtr->tmpInSize += sizeToCopy;
- if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) { /* not enough input to get full sBlockSize; wait for more */
+ if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) {
+ /* not enough input to get full sBlockSize; wait for more */
nextSrcSizeHint = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
doAnotherStage = 0;
break;
diff --git a/lib/lz4frame.h b/lib/lz4frame.h
index 9a2130a..b1719e2 100644
--- a/lib/lz4frame.h
+++ b/lib/lz4frame.h
@@ -364,14 +364,11 @@ LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx,
/*! LZ4F_resetDecompressionContext() : v1.8.0
- * When decompression ends successfully,
- * it's possible to start a new decompression immediately
- * re-using the same context.
- * However, in case of an error, the context is left in "undefined" state.
+ * In case of an error, the context is left in "undefined" state.
* In which case, it's necessary to reset it, before re-using it.
* This method can also be used to abruptly stop an unfinished decompression,
- * and start a new on the same context. */
-LZ4FLIB_API LZ4F_errorCode_t LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);
+ * and start a new with the same context. */
+LZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx); /* always successful */
diff --git a/lib/lz4frame_static.h b/lib/lz4frame_static.h
index 8ea496d..d3bae82 100644
--- a/lib/lz4frame_static.h
+++ b/lib/lz4frame_static.h
@@ -50,15 +50,6 @@ extern "C" {
#include "lz4frame.h"
-/* --- Experimental functions --- */
-/* LZ4F_resetDecompressionContext() :
- * LZ4F_decompress() does not guarantee to leave dctx in clean state in case of errors.
- * In order to re-use a dctx after a decompression error,
- * use LZ4F_resetDecompressionContext() first.
- * dctx will be able to start decompression on a new frame */
-LZ4FLIB_API LZ4F_errorCode_t LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);
-
-
/* --- Error List --- */
#define LZ4F_LIST_ERRORS(ITEM) \
ITEM(OK_NoError) \
diff --git a/tests/frametest.c b/tests/frametest.c
index 04597a4..538bedc 100644
--- a/tests/frametest.c
+++ b/tests/frametest.c
@@ -40,6 +40,7 @@
#include <stdio.h> /* fprintf */
#include <string.h> /* strcmp */
#include <time.h> /* clock_t, clock(), CLOCKS_PER_SEC */
+#include <assert.h>
#include "lz4frame_static.h"
#include "lz4.h" /* LZ4_VERSION_STRING */
#define XXH_STATIC_LINKING_ONLY
@@ -67,7 +68,6 @@ static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
#define GB *(1U<<30)
static const U32 nbTestsDefault = 256 KB;
-#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
#define FUZ_COMPRESSIBILITY_DEFAULT 50
static const U32 prime1 = 2654435761U;
static const U32 prime2 = 2246822519U;
@@ -166,7 +166,7 @@ static unsigned FUZ_highbit(U32 v32)
*********************************************************/
int basicTests(U32 seed, double compressibility)
{
- int testResult = 0;
+#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
void* const compressedBuffer = malloc(cBuffSize);
@@ -176,9 +176,10 @@ int basicTests(U32 seed, double compressibility)
LZ4F_decompressionContext_t dCtx = NULL;
LZ4F_compressionContext_t cctx = NULL;
U64 crcOrig;
-
+ int basicTests_error = 0;
LZ4F_preferences_t prefs;
memset(&prefs, 0, sizeof(prefs));
+
if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
goto _output_error;
@@ -198,7 +199,7 @@ int basicTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
if (LZ4F_isError(cSize)) goto _output_error;
- DISPLAYLEVEL(3, "Compressed null content into a %i bytes frame \n", (int)cSize);
+ DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
{ LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
@@ -236,8 +237,6 @@ int basicTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "Decompression test : \n");
{ size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
size_t compressedBufferSize = cSize;
- BYTE* ip = (BYTE*)compressedBuffer;
- BYTE* const iend = (BYTE*)compressedBuffer + cSize;
LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
if (LZ4F_isError(errorCode)) goto _output_error;
@@ -280,6 +279,7 @@ int basicTests(U32 seed, double compressibility)
{ size_t oSize = 0;
size_t iSize = 0;
LZ4F_frameInfo_t fi;
+ const BYTE* ip = (BYTE*)compressedBuffer;
DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL);
@@ -315,10 +315,30 @@ int basicTests(U32 seed, double compressibility)
ip += iSize;
}
+ DISPLAYLEVEL(3, "Decode a buggy input : ");
+ assert(COMPRESSIBLE_NOISE_LENGTH > 64);
+ assert(cSize > 48);
+ memcpy(decodedBuffer, (char*)compressedBuffer+16, 32); /* save correct data */
+ memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32); /* insert noise */
+ { size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
+ size_t cbSize = cSize;
+ size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
+ compressedBuffer, &cbSize,
+ NULL);
+ if (!LZ4F_isError(decompressError)) goto _output_error;
+ DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
+ }
+ memcpy((char*)compressedBuffer+16, decodedBuffer, 32); /* restore correct data */
+
+ DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
+ LZ4F_resetDecompressionContext(dCtx); /* always successful */
+
DISPLAYLEVEL(3, "Byte after byte : ");
{ BYTE* const ostart = (BYTE*)decodedBuffer;
BYTE* op = ostart;
BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
+ const BYTE* ip = compressedBuffer;
+ const BYTE* const iend = ip + cSize;
while (ip < iend) {
size_t oSize = oend-op;
size_t iSize = 1;
@@ -330,11 +350,7 @@ int basicTests(U32 seed, double compressibility)
{ U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
if (crcDest != crcOrig) goto _output_error; }
DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), COMPRESSIBLE_NOISE_LENGTH);
- }
-
- errorCode = LZ4F_freeDecompressionContext(dCtx);
- if (LZ4F_isError(errorCode)) goto _output_error;
- dCtx = NULL;
+ }
}
DISPLAYLEVEL(3, "Using 64 KB block : ");
@@ -366,9 +382,6 @@ int basicTests(U32 seed, double compressibility)
const BYTE* ip = (const BYTE*)compressedBuffer;
const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
- { LZ4F_errorCode_t const createError = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
- if (LZ4F_isError(createError)) goto _output_error; }
-
DISPLAYLEVEL(3, "random segment sizes : ");
while (ip < iend) {
unsigned const nbBits = FUZ_rand(&randState) % maxBits;
@@ -552,10 +565,10 @@ _end:
free(decodedBuffer);
LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
LZ4F_freeCompressionContext(cctx); cctx = NULL;
- return testResult;
+ return basicTests_error;
_output_error:
- testResult = 1;
+ basicTests_error = 1;
DISPLAY("Error detected ! \n");
goto _end;
}