summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Collet <Cyan4973@users.noreply.github.com>2019-04-15 22:32:03 (GMT)
committerGitHub <noreply@github.com>2019-04-15 22:32:03 (GMT)
commita067441f562d2c211c3a5675b9d4057218e2af09 (patch)
tree570be2e40dea0697e773d709d00e5a1e46afaebb
parentac5d2629c1689efb0864225a71465e8d27526bf3 (diff)
parent920c988669663708bc5ac8db3ba18bd78eebe499 (diff)
downloadlz4-a067441f562d2c211c3a5675b9d4057218e2af09.zip
lz4-a067441f562d2c211c3a5675b9d4057218e2af09.tar.gz
lz4-a067441f562d2c211c3a5675b9d4057218e2af09.tar.bz2
Merge pull request #669 from lz4/fixframe
Fix lz4frame inefficiency
-rw-r--r--lib/lz4.c77
-rw-r--r--lib/lz4.h27
-rw-r--r--lib/lz4hc.c31
-rw-r--r--tests/fuzzer.c6
4 files changed, 67 insertions, 74 deletions
diff --git a/lib/lz4.c b/lib/lz4.c
index 031f8c1..693bdaf 100644
--- a/lib/lz4.c
+++ b/lib/lz4.c
@@ -32,14 +32,6 @@
- LZ4 source repository : https://github.com/lz4/lz4
*/
-/*
- * LZ4_SRC_INCLUDED:
- * Amalgamation flag, whether lz4.c is included
- */
-#ifndef LZ4_SRC_INCLUDED
-# define LZ4_SRC_INCLUDED 1
-#endif
-
/*-************************************
* Tuning parameters
**************************************/
@@ -98,6 +90,14 @@
/*-************************************
* Dependency
**************************************/
+/*
+ * LZ4_SRC_INCLUDED:
+ * Amalgamation flag, whether lz4.c is included
+ */
+#ifndef LZ4_SRC_INCLUDED
+# define LZ4_SRC_INCLUDED 1
+#endif
+
#define LZ4_STATIC_LINKING_ONLY
#define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */
#include "lz4.h"
@@ -177,7 +177,7 @@
/*-************************************
-* Basic Types
+* Types
**************************************/
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# include <stdint.h>
@@ -202,6 +202,12 @@
typedef size_t reg_t; /* 32-bits in x32 mode */
#endif
+typedef enum {
+ notLimited = 0,
+ limitedOutput = 1,
+ fillOutput = 2
+} limitedOutput_directive;
+
/*-************************************
* Reading and writing into memory
@@ -549,13 +555,6 @@ static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression ru
/*-************************************
* Local Structures and types
**************************************/
-typedef enum {
- noLimit = 0,
- notLimited = 1,
- limitedOutput = 2,
- fillOutput = 3,
- limitedDestSize = 4
-} limitedOutput_directive;
typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;
/**
@@ -761,9 +760,9 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
const char* const source,
char* const dest,
const int inputSize,
- int *inputConsumed, /* only written when outputLimited == fillOutput */
+ int *inputConsumed, /* only written when outputDirective == fillOutput */
const int maxOutputSize,
- const limitedOutput_directive outputLimited,
+ const limitedOutput_directive outputDirective,
const tableType_t tableType,
const dict_directive dictDirective,
const dictIssue_directive dictIssue,
@@ -806,7 +805,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType);
/* If init conditions are not met, we don't have to mark stream
* as having dirty context, since no action was taken yet */
- if (outputLimited == fillOutput && maxOutputSize < 1) return 0; /* Impossible to store anything */
+ if (outputDirective == fillOutput && maxOutputSize < 1) return 0; /* Impossible to store anything */
if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */
if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
if (tableType==byPtr) assert(dictDirective==noDict); /* only supported use case with byPtr */
@@ -923,11 +922,11 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
/* Encode Literals */
{ unsigned const litLength = (unsigned)(ip - anchor);
token = op++;
- if ((outputLimited == limitedOutput) && /* Check output buffer overflow */
- (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
- goto _failure;
+ if ((outputDirective == limitedOutput) && /* Check output buffer overflow */
+ (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) )
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
- if ((outputLimited == fillOutput) &&
+ if ((outputDirective == fillOutput) &&
(unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {
op--;
goto _last_literals;
@@ -956,7 +955,7 @@ _next_match:
* - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written
*/
- if ((outputLimited == fillOutput) &&
+ if ((outputDirective == fillOutput) &&
(op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit)) {
/* the match was too close to the end, rewind and go to last literals */
op = token;
@@ -996,15 +995,16 @@ _next_match:
DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH);
}
- if ((outputLimited) && /* Check output buffer overflow */
+ if ((outputDirective) && /* Check output buffer overflow */
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) {
- if (outputLimited == limitedOutput)
- goto _failure;
- if (outputLimited == fillOutput) {
+ if (outputDirective == fillOutput) {
/* Match description too long : reduce it */
U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 2 - 1 - LASTLITERALS) * 255;
ip -= matchCode - newMatchCode;
matchCode = newMatchCode;
+ } else {
+ assert(outputDirective == limitedOutput);
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
}
}
if (matchCode >= ML_MASK) {
@@ -1089,16 +1089,17 @@ _next_match:
_last_literals:
/* Encode Last Literals */
{ size_t lastRun = (size_t)(iend - anchor);
- if ( (outputLimited) && /* Check output buffer overflow */
+ if ( (outputDirective) && /* Check output buffer overflow */
(op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {
- if (outputLimited == fillOutput) {
+ if (outputDirective == fillOutput) {
/* adapt lastRun to fill 'dst' */
assert(olimit >= op);
lastRun = (size_t)(olimit-op) - 1;
lastRun -= (lastRun+240)/255;
+ } else {
+ assert(outputDirective == limitedOutput);
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
}
- if (outputLimited == limitedOutput)
- goto _failure;
}
if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK;
@@ -1113,18 +1114,13 @@ _last_literals:
op += lastRun;
}
- if (outputLimited == fillOutput) {
+ if (outputDirective == fillOutput) {
*inputConsumed = (int) (((const char*)ip)-source);
}
DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, (int)(((char*)op) - dest));
result = (int)(((char*)op) - dest);
assert(result > 0);
return result;
-
-_failure:
- /* Mark stream as having dirty context, so, it has to be fully reset */
- cctx->dirty = 1;
- return 0;
}
@@ -1422,7 +1418,10 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)
}
-int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,
+ const char* source, char* dest,
+ int inputSize, int maxOutputSize,
+ int acceleration)
{
const tableType_t tableType = byU32;
LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse;
diff --git a/lib/lz4.h b/lib/lz4.h
index 23b5ac5..1589be9 100644
--- a/lib/lz4.h
+++ b/lib/lz4.h
@@ -631,11 +631,11 @@ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4
LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
/*! LZ4_decompress_fast() : **unsafe!**
- * These functions used to be a bit faster than LZ4_decompress_safe(),
- * but situation has changed in recent versions.
- * Now, `LZ4_decompress_safe()` is as fast and sometimes even faster than `LZ4_decompress_fast()`.
- * Moreover, LZ4_decompress_safe() is protected vs malformed input, while `LZ4_decompress_fast()` is not, making it a security liability.
+ * These functions are generally slightly faster than LZ4_decompress_safe(),
+ * though the difference is small (generally ~5%).
+ * However, the real cost is a risk : LZ4_decompress_safe() is protected vs malformed input, while `LZ4_decompress_fast()` is not, making it a security liability.
* As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.
+ * These functions will generate a deprecation warning in the future.
*
* Last LZ4_decompress_fast() specificity is that it can decompress a block without knowing its compressed size.
* Note that even that functionality could be achieved in a more secure manner if need be,
@@ -648,18 +648,19 @@ LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4
* The function expects to finish at block's end exactly.
* If the source stream is detected malformed, the function stops decoding and returns a negative result.
* note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.
- * However, since it doesn't know its 'src' size, it may read an unknown amount of input, and overflow input buffer.
- * Also, since match offsets are not validated, match reads from 'src' may underflow.
- * These issues never happen if input data is correct.
+ * However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.
+ * Also, since match offsets are not validated, match reads from 'src' may underflow too.
+ * These issues never happen if input (compressed) data is correct.
* But they may happen if input data is invalid (error or intentional tampering).
* As a consequence, use these functions in trusted environments with trusted data **only**.
*/
-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") LZ4LIB_API
-int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") LZ4LIB_API
-int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);
-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead") LZ4LIB_API
-int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);
+
+/* LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") */
+LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
+/* LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") */
+LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);
+/* LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead") */
+LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);
/*! LZ4_resetStream() :
* An LZ4_stream_t structure must be initialized at least once.
diff --git a/lib/lz4hc.c b/lib/lz4hc.c
index 4e3573a..f6ed779 100644
--- a/lib/lz4hc.c
+++ b/lib/lz4hc.c
@@ -63,13 +63,6 @@
/*=== Enums ===*/
typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
-#ifndef LZ4_SRC_INCLUDED
-typedef enum {
- noLimit = 0,
- limitedOutput = 1,
- limitedDestSize = 2
-} limitedOutput_directive;
-#endif
#define LZ4_COMMONDEFS_ONLY
@@ -512,7 +505,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
/* init */
*srcSizePtr = 0;
- if (limit == limitedDestSize) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
+ if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
/* Main Loop */
@@ -659,7 +652,7 @@ _last_literals:
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + litLength + lastRunSize;
- if (limit == limitedDestSize) oend += LASTLITERALS; /* restore correct value */
+ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
if (limit && (op + totalSize > oend)) {
if (limit == limitedOutput) return 0; /* Check output limit */
/* adapt lastRunSize to fill 'dest' */
@@ -686,7 +679,7 @@ _last_literals:
return (int) (((char*)op)-dest);
_dest_overflow:
- if (limit == limitedDestSize) {
+ if (limit == fillOutput) {
op = optr; /* restore correct out pointer */
goto _last_literals;
}
@@ -738,7 +731,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d)", ctx, src, *srcSizePtr);
- if (limit == limitedDestSize && dstCapacity < 1) return 0; /* Impossible to store anything */
+ if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
ctx->end += *srcSizePtr;
@@ -855,7 +848,7 @@ int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* ds
if (dstCapacity < LZ4_compressBound(srcSize))
return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
else
- return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, noLimit);
+ return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
}
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
@@ -887,7 +880,7 @@ int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* s
if (ctx==NULL) return 0; /* init failure */
LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
LZ4_setCompressionLevel(ctx, cLevel);
- return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, limitedDestSize);
+ return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
}
@@ -1056,12 +1049,12 @@ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src,
if (dstCapacity < LZ4_compressBound(srcSize))
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
else
- return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, noLimit);
+ return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
}
int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
{
- return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, limitedDestSize);
+ return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
}
@@ -1137,7 +1130,7 @@ int LZ4_freeHC (void* LZ4HC_Data)
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
{
- return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, noLimit);
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
}
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
@@ -1247,7 +1240,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
/* init */
DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
*srcSizePtr = 0;
- if (limit == limitedDestSize) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
+ if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
/* Main Loop */
@@ -1447,7 +1440,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + litLength + lastRunSize;
- if (limit == limitedDestSize) oend += LASTLITERALS; /* restore correct value */
+ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
if (limit && (op + totalSize > oend)) {
if (limit == limitedOutput) return 0; /* Check output limit */
/* adapt lastRunSize to fill 'dst' */
@@ -1474,7 +1467,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
return (int) ((char*)op-dst);
_dest_overflow:
- if (limit == limitedDestSize) {
+ if (limit == fillOutput) {
op = opSaved; /* restore correct out pointer */
goto _last_literals;
}
diff --git a/tests/fuzzer.c b/tests/fuzzer.c
index 8e25615..3128e6d 100644
--- a/tests/fuzzer.c
+++ b/tests/fuzzer.c
@@ -762,7 +762,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c
LZ4_attach_dictionary(&LZ4_stream, &LZ4dict);
ret = LZ4_compress_fast_continue(&LZ4_stream, block, compressedBuffer, blockSize, blockContinueCompressedSize-1, 1);
FUZ_CHECKTEST(ret>0, "LZ4_compress_fast_continue using extDictCtx should fail : one missing byte for output buffer : %i written, %i buffer", ret, blockContinueCompressedSize);
- FUZ_CHECKTEST(!LZ4_stream.internal_donotuse.dirty, "context should be dirty");
+ /* note : context is no longer dirty after a failed compressed block */
FUZ_DISPLAYTEST();
LZ4_resetStream_fast(&LZ4_stream);
@@ -840,7 +840,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c
LZ4_loadDictHC(&LZ4dictHC, dict, dictSize);
ret = LZ4_compress_HC_continue(&LZ4dictHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1);
FUZ_CHECKTEST(ret>0, "LZ4_compress_HC_continue using ExtDict should fail : one missing byte for output buffer (expected %i, but result=%i)", blockContinueCompressedSize, ret);
- FUZ_CHECKTEST(!LZ4dictHC.internal_donotuse.dirty, "Context should be dirty");
+ /* note : context is no longer dirty after a failed compressed block */
FUZ_DISPLAYTEST("LZ4_compress_HC_continue with same external dictionary, and output buffer exactly the right size");
LZ4_loadDictHC(&LZ4dictHC, dict, dictSize);
@@ -877,7 +877,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c
LZ4_attach_HC_dictionary(&LZ4_streamHC, &LZ4dictHC);
ret = LZ4_compress_HC_continue(&LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize-1);
FUZ_CHECKTEST(ret>0, "LZ4_compress_HC_continue using ExtDictCtx should fail : one missing byte for output buffer (%i != %i)", ret, blockContinueCompressedSize);
- FUZ_CHECKTEST(!LZ4_streamHC.internal_donotuse.dirty, "Context should be dirty");
+ /* note : context is no longer dirty after a failed compressed block */
FUZ_DISPLAYTEST();
LZ4_resetStreamHC_fast (&LZ4_streamHC, compressionLevel);