Merge pull request #918 from lz4/usan_null

Properly fix #847
This commit is contained in:
Yann Collet 2020-09-17 20:23:06 -07:00 committed by GitHub
commit d568a6d15c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 12 deletions

View File

@ -124,8 +124,8 @@ check:
.PHONY: test
test:
$(MAKE) -C $(TESTDIR) $@
$(MAKE) -C $(EXDIR) $@
CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(MAKE) -C $(TESTDIR) $@
CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(MAKE) -C $(EXDIR) $@
clangtest: CFLAGS ?= -O3
clangtest: CFLAGS += -Werror -Wconversion -Wno-sign-conversion
@ -142,8 +142,11 @@ clangtest-native: clean
@CFLAGS="-O3 -Werror -Wconversion -Wno-sign-conversion" $(MAKE) -C $(PRGDIR) native CC=clang
@CFLAGS="-O3 -Werror -Wconversion -Wno-sign-conversion" $(MAKE) -C $(TESTDIR) native CC=clang
usan: CC = clang
usan: CFLAGS = -O3 -g -fsanitize=undefined -fno-sanitize-recover=undefined -fsanitize-recover=pointer-overflow
usan: LDFLAGS = $(CFLAGS)
usan: clean
CC=clang CFLAGS="-O3 -g -fsanitize=undefined" $(MAKE) test FUZZER_TIME="-T30s" NB_LOOPS=-i1
CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" $(MAKE) test FUZZER_TIME="-T30s" NB_LOOPS=-i1
usan32: clean
CFLAGS="-m32 -O3 -g -fsanitize=undefined" $(MAKE) test FUZZER_TIME="-T30s" NB_LOOPS=-i1

View File

@ -819,8 +819,12 @@ LZ4_prepareTable(LZ4_stream_t_internal* const cctx,
}
/** LZ4_compress_generic() :
inlined, to ensure branches are decided at compilation time */
LZ4_FORCE_INLINE int LZ4_compress_generic(
* inlined, to ensure branches are decided at compilation time.
* Presumed already validated at this stage:
* - source != NULL
* - inputSize > 0
*/
LZ4_FORCE_INLINE int LZ4_compress_generic_validated(
LZ4_stream_t_internal* const cctx,
const char* const source,
char* const dest,
@ -867,11 +871,11 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
U32 offset = 0;
U32 forwardH;
DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType);
DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType);
assert(ip != NULL);
/* If init conditions are not met, we don't have to mark stream
* as having dirty context, since no action was taken yet */
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 */
assert(acceleration >= 1);
@ -1204,12 +1208,52 @@ _last_literals:
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);
DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result);
return result;
}
/** LZ4_compress_generic() :
* inlined, to ensure branches are decided at compilation time;
* takes care of src == (NULL, 0)
* and forward the rest to LZ4_compress_generic_validated */
LZ4_FORCE_INLINE int LZ4_compress_generic(
LZ4_stream_t_internal* const cctx,
const char* const src,
char* const dst,
const int srcSize,
int *inputConsumed, /* only written when outputDirective == fillOutput */
const int dstCapacity,
const limitedOutput_directive outputDirective,
const tableType_t tableType,
const dict_directive dictDirective,
const dictIssue_directive dictIssue,
const int acceleration)
{
DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i",
srcSize, dstCapacity);
if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported srcSize, too large (or negative) */
if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */
DEBUGLOG(5, "Generating an empty block");
assert(outputDirective == notLimited || dstCapacity >= 1);
assert(dst != NULL);
dst[0] = 0;
if (outputDirective == fillOutput) {
assert (inputConsumed != NULL);
*inputConsumed = 0;
}
return 1;
}
assert(src != NULL);
return LZ4_compress_generic_validated(cctx, src, dst, srcSize,
inputConsumed, /* only written into if outputDirective == fillOutput */
dstCapacity, outputDirective,
tableType, dictDirective, dictIssue, acceleration);
}
int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
{
@ -2077,6 +2121,7 @@ LZ4_decompress_generic(
/* end of decoding */
if (endOnInput) {
DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst));
return (int) (((char*)op)-dst); /* Nb of output bytes decoded */
} else {
return (int) (((const char*)ip)-src); /* Nb of input bytes read */

View File

@ -750,6 +750,7 @@ static size_t LZ4F_makeBlock(void* dst,
(int)(srcSize), (int)(srcSize-1),
level, cdict);
if (cSize == 0) { /* compression failed */
DEBUGLOG(5, "LZ4F_makeBlock: compression failed, creating a raw block (size %u)", (U32)srcSize);
cSize = (U32)srcSize;
LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG);
memcpy(cSizePtr+BHSize, src, srcSize);
@ -1487,15 +1488,17 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU;
size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize;
if (blockHeader==0) { /* frameEnd signal, no more block */
DEBUGLOG(5, "end of frame");
dctx->dStage = dstage_getSuffix;
break;
}
if (nextCBlockSize > dctx->maxBlockSize) {
return err0r(LZ4F_ERROR_maxBlockSize_invalid);
}
if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
if (blockHeader & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
/* next block is uncompressed */
dctx->tmpInTarget = nextCBlockSize;
DEBUGLOG(5, "next block is uncompressed (size %u)", (U32)nextCBlockSize);
if (dctx->frameInfo.blockChecksumFlag) {
(void)XXH32_reset(&dctx->blockChecksum, 0);
}

1
tests/.gitignore vendored
View File

@ -11,6 +11,7 @@ fasttest
roundTripTest
checkTag
checkFrame
decompress-partial
# test artefacts
tmp*

View File

@ -35,7 +35,7 @@ PYTHON ?= python3
DEBUGLEVEL?= 1
DEBUGFLAGS = -g -DLZ4_DEBUG=$(DEBUGLEVEL)
CFLAGS ?= -O3 # can select custom optimization flags. For example : CFLAGS=-O2 make
CFLAGS ?= -O3 # can select custom optimization flags. Example : CFLAGS=-O2 make
CFLAGS += -Wall -Wextra -Wundef -Wcast-qual -Wcast-align -Wshadow \
-Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes \
-Wpointer-arith -Wstrict-aliasing=1

View File

@ -785,7 +785,7 @@ typedef enum { o_contiguous, o_noncontiguous, o_overwrite } o_scenario_e;
static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, o_scenario_e o_scenario)
{
if (displayLevel >= 5) {
if (displayLevel >= 2) {
size_t p=0;
const BYTE* b1=(const BYTE*)buff1;
const BYTE* b2=(const BYTE*)buff2;
@ -862,8 +862,10 @@ size_t test_lz4f_decompression_wBuffers(
"Decompression overwrites beyond assigned dst size",
op[oSizeMax], mark);
}
if (LZ4F_getErrorCode(moreToFlush) == LZ4F_ERROR_contentChecksum_invalid)
if (LZ4F_getErrorCode(moreToFlush) == LZ4F_ERROR_contentChecksum_invalid) {
DISPLAYLEVEL(2, "checksum error detected \n");
locateBuffDiff(srcRef, dst, decompressedSize, o_scenario);
}
if (LZ4F_isError(moreToFlush)) return moreToFlush;
XXH64_update(&xxh64, op, oSize);