diff options
Diffstat (limited to 'tests/fuzzer.c')
-rw-r--r-- | tests/fuzzer.c | 303 |
1 files changed, 243 insertions, 60 deletions
diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 8a095c4..a824813 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -341,7 +341,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c exit(1); \ } -# define FUZ_CHECKTEST(cond, ...) { if (cond) { EXIT_MSG(__VA_ARGS__) } } +# define FUZ_CHECKTEST(cond, ...) if (cond) { EXIT_MSG(__VA_ARGS__) } # define FUZ_DISPLAYTEST(...) { \ testNb++; \ @@ -446,10 +446,10 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST(); decodedBuffer[srcSize] = canary; { int const dSize = LZ4_decompress_safe(compressedBuffer, decodedBuffer, cSize, srcSize); - FUZ_CHECKTEST(dSize<0, "LZ4_decompress_safe() failed on data compressed by LZ4_compressHC_destSize"); - FUZ_CHECKTEST(dSize!=srcSize, "LZ4_decompress_safe() failed : did not fully decompressed data"); + FUZ_CHECKTEST(dSize<0, "LZ4_decompress_safe failed (%i) on data compressed by LZ4_compressHC_destSize", dSize); + FUZ_CHECKTEST(dSize!=srcSize, "LZ4_decompress_safe failed : decompressed %i bytes, was supposed to decompress %i bytes", dSize, srcSize); } - FUZ_CHECKTEST(decodedBuffer[srcSize] != canary, "LZ4_decompress_safe() overwrite dst buffer !"); + FUZ_CHECKTEST(decodedBuffer[srcSize] != canary, "LZ4_decompress_safe overwrite dst buffer !"); { U32 const crcDec = XXH32(decodedBuffer, (size_t)srcSize, 0); FUZ_CHECKTEST(crcDec!=crcBase, "LZ4_decompress_safe() corrupted decoded data"); } } @@ -618,13 +618,16 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Test partial decoding => must work */ FUZ_DISPLAYTEST("test LZ4_decompress_safe_partial"); - { size_t const missingBytes = FUZ_rand(&randState) % (unsigned)blockSize; - int const targetSize = (int)((size_t)blockSize - missingBytes); + { size_t const missingOutBytes = FUZ_rand(&randState) % (unsigned)blockSize; + int const targetSize = (int)((size_t)blockSize - missingOutBytes); + size_t const extraneousInBytes = FUZ_rand(&randState) % 2; + int const inCSize = (int)((size_t)compressedSize + extraneousInBytes); char const sentinel = decodedBuffer[targetSize] = block[targetSize] ^ 0x5A; - int const decResult = LZ4_decompress_safe_partial(compressedBuffer, decodedBuffer, compressedSize, targetSize, blockSize); + int const decResult = LZ4_decompress_safe_partial(compressedBuffer, decodedBuffer, inCSize, targetSize, blockSize); FUZ_CHECKTEST(decResult<0, "LZ4_decompress_safe_partial failed despite valid input data (error:%i)", decResult); FUZ_CHECKTEST(decResult != targetSize, "LZ4_decompress_safe_partial did not regenerated required amount of data (%i < %i <= %i)", decResult, targetSize, blockSize); FUZ_CHECKTEST(decodedBuffer[targetSize] != sentinel, "LZ4_decompress_safe_partial overwrite beyond requested size (though %i <= %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(memcmp(block, decodedBuffer, (size_t)targetSize), "LZ4_decompress_safe_partial: corruption detected in regenerated data"); } /* Test Compression with limited output size */ @@ -787,7 +790,6 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c LZ4_attach_dictionary(&LZ4_stream, &LZ4dictBody); blockContinueCompressedSize = LZ4_compress_fast_continue(&LZ4_stream, block, compressedBuffer, blockSize, (int)compressedBufferSize, 1); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_fast_continue using extDictCtx failed"); - FUZ_CHECKTEST(LZ4_stream.internal_donotuse.dirty, "context should be good"); /* In the future, it might be desirable to let extDictCtx mode's * output diverge from the output generated by regular extDict mode. @@ -812,7 +814,6 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(ret<=0, "LZ4_compress_fast_continue using extDictCtx should work : enough size available within output buffer"); FUZ_CHECKTEST(ret != expectedSize, "LZ4_compress_fast_continue using extDictCtx produced different-sized output"); FUZ_CHECKTEST(XXH32(compressedBuffer, (size_t)ret, 0) != expectedCrc, "LZ4_compress_fast_continue using extDictCtx produced different output"); - FUZ_CHECKTEST(LZ4_stream.internal_donotuse.dirty, "context should be good"); FUZ_DISPLAYTEST(); LZ4_resetStream_fast(&LZ4_stream); @@ -822,7 +823,6 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(ret<=0, "LZ4_compress_fast_continue using extDictCtx with re-used context should work : enough size available within output buffer"); FUZ_CHECKTEST(ret != expectedSize, "LZ4_compress_fast_continue using extDictCtx produced different-sized output"); FUZ_CHECKTEST(XXH32(compressedBuffer, (size_t)ret, 0) != expectedCrc, "LZ4_compress_fast_continue using extDictCtx produced different output"); - FUZ_CHECKTEST(LZ4_stream.internal_donotuse.dirty, "context should be good"); } /* Decompress with dictionary as external */ @@ -859,12 +859,12 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(decodedBuffer[blockSize-1], "LZ4_decompress_safe_usingDict overrun specified output buffer size"); FUZ_DISPLAYTEST("LZ4_decompress_safe_usingDict with a too small output buffer"); - { U32 const missingBytes = (FUZ_rand(&randState) & 0xF) + 2; - if ((U32)blockSize > missingBytes) { - decodedBuffer[(U32)blockSize-missingBytes] = 0; + { int const missingBytes = (FUZ_rand(&randState) & 0xF) + 2; + if (blockSize > missingBytes) { + decodedBuffer[blockSize-missingBytes] = 0; ret = LZ4_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, blockSize-missingBytes, dict, dictSize); - FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe_usingDict should have failed : output buffer too small (-%u byte)", missingBytes); - FUZ_CHECKTEST(decodedBuffer[blockSize-missingBytes], "LZ4_decompress_safe_usingDict overrun specified output buffer size (-%u byte) (blockSize=%i)", missingBytes, blockSize); + FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe_usingDict should have failed : output buffer too small (-%i byte)", missingBytes); + FUZ_CHECKTEST(decodedBuffer[blockSize-missingBytes], "LZ4_decompress_safe_usingDict overrun specified output buffer size (-%i byte) (blockSize=%i)", missingBytes, blockSize); } } /* Compress HC using External dictionary */ @@ -931,7 +931,8 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c LZ4_resetStreamHC_fast (LZ4_streamHC, compressionLevel); LZ4_attach_HC_dictionary(LZ4_streamHC, LZ4dictHC); ret = LZ4_compress_HC_continue(LZ4_streamHC, block, compressedBuffer, blockSize, blockContinueCompressedSize); - FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue using ExtDictCtx and fast reset size is different (%i != %i)", ret, blockContinueCompressedSize); + FUZ_CHECKTEST(ret!=blockContinueCompressedSize, "LZ4_compress_HC_continue using ExtDictCtx and fast reset size is different (%i != %i)", + ret, blockContinueCompressedSize); FUZ_CHECKTEST(ret<=0, "LZ4_compress_HC_continue using ExtDictCtx and fast reset should work : enough size available within output buffer"); FUZ_CHECKTEST(LZ4_streamHC->internal_donotuse.dirty, "Context should be clean"); @@ -951,13 +952,14 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* Compress HC continue destSize */ FUZ_DISPLAYTEST(); - { int const availableSpace = (int)(FUZ_rand(&randState) % blockSize) + 5; + { int const availableSpace = (int)(FUZ_rand(&randState) % (U32)blockSize) + 5; int consumedSize = blockSize; FUZ_DISPLAYTEST(); LZ4_loadDictHC(LZ4dictHC, dict, dictSize); LZ4_setCompressionLevel(LZ4dictHC, compressionLevel); blockContinueCompressedSize = LZ4_compress_HC_continue_destSize(LZ4dictHC, block, compressedBuffer, &consumedSize, availableSpace); - DISPLAYLEVEL(5, " LZ4_compress_HC_continue_destSize : compressed %6i/%6i into %6i/%6i at cLevel=%i\n", consumedSize, blockSize, blockContinueCompressedSize, availableSpace, compressionLevel); + DISPLAYLEVEL(5, " LZ4_compress_HC_continue_destSize : compressed %6i/%6i into %6i/%6i at cLevel=%i \n", + consumedSize, blockSize, blockContinueCompressedSize, availableSpace, compressionLevel); FUZ_CHECKTEST(blockContinueCompressedSize==0, "LZ4_compress_HC_continue_destSize failed"); FUZ_CHECKTEST(blockContinueCompressedSize > availableSpace, "LZ4_compress_HC_continue_destSize write overflow"); FUZ_CHECKTEST(consumedSize > blockSize, "LZ4_compress_HC_continue_destSize read overflow"); @@ -965,7 +967,7 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_DISPLAYTEST(); decodedBuffer[consumedSize] = 0; ret = LZ4_decompress_safe_usingDict(compressedBuffer, decodedBuffer, blockContinueCompressedSize, consumedSize, dict, dictSize); - FUZ_CHECKTEST(ret!=consumedSize, "LZ4_decompress_safe_usingDict did not regenerate original data"); + FUZ_CHECKTEST(ret != consumedSize, "LZ4_decompress_safe_usingDict regenerated %i bytes (%i expected)", ret, consumedSize); FUZ_CHECKTEST(decodedBuffer[consumedSize], "LZ4_decompress_safe_usingDict overrun specified output buffer size") { U32 const crcSrc = XXH32(block, (size_t)consumedSize, 0); U32 const crcDst = XXH32(decodedBuffer, (size_t)consumedSize, 0); @@ -977,10 +979,14 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c /* ***** End of tests *** */ /* Fill stats */ - bytes += blockSize; - cbytes += compressedSize; - hcbytes += HCcompressedSize; - ccbytes += blockContinueCompressedSize; + assert(blockSize >= 0); + bytes += (unsigned)blockSize; + assert(compressedSize >= 0); + cbytes += (unsigned)compressedSize; + assert(HCcompressedSize >= 0); + hcbytes += (unsigned)HCcompressedSize; + assert(blockContinueCompressedSize >= 0); + ccbytes += (unsigned)blockContinueCompressedSize; } if (nbCycles<=1) nbCycles = cycleNb; /* end by time */ @@ -1051,6 +1057,26 @@ static void FUZ_unitTests(int compressionLevel) FUZ_CHECKTEST(r >= 0, "LZ4_decompress_safe() should fail"); } } + + /* to be tested with undefined sanitizer */ + DISPLAYLEVEL(3, "LZ4_compress_default() with NULL input:"); + { int const maxCSize = LZ4_compressBound(0); + int const cSize = LZ4_compress_default(NULL, testCompressed, 0, maxCSize); + FUZ_CHECKTEST(!(cSize==1 && testCompressed[0]==0), + "compressing empty should give byte 0" + " (maxCSize == %i) (cSize == %i) (byte == 0x%02X)", + maxCSize, cSize, testCompressed[0]); + } + DISPLAYLEVEL(3, " OK \n"); + + DISPLAYLEVEL(3, "LZ4_compress_default() with both NULL input and output:"); + { int const cSize = LZ4_compress_default(NULL, NULL, 0, 0); + FUZ_CHECKTEST(cSize != 0, + "compressing into NULL must fail" + " (cSize == %i != 0)", cSize); + } + DISPLAYLEVEL(3, " OK \n"); + /* in-place compression test */ DISPLAYLEVEL(3, "in-place compression using LZ4_compress_default() :"); { int const sampleSize = 65 KB; @@ -1071,7 +1097,7 @@ static void FUZ_unitTests(int compressionLevel) { int const dSize = LZ4_decompress_safe(testCompressed, testVerify, cSize, testInputSize); assert(dSize == sampleSize); /* correct size */ { XXH32_hash_t const crcCheck = XXH32(testVerify, (size_t)dSize, 0); - assert(crcCheck == crcOrig); + FUZ_CHECKTEST(crcCheck != crcOrig, "LZ4_decompress_safe decompression corruption"); } } } DISPLAYLEVEL(3, " OK \n"); @@ -1095,32 +1121,67 @@ static void FUZ_unitTests(int compressionLevel) { int const dSize = LZ4_decompress_safe(startInput, testVerify, cSize, sampleSize); assert(dSize == sampleSize); /* correct size */ { XXH64_hash_t const crcCheck = XXH64(testVerify, (size_t)dSize, 0); - assert(crcCheck == crcOrig); + FUZ_CHECKTEST(crcCheck != crcOrig, "LZ4_decompress_safe decompression corruption"); } } } } } DISPLAYLEVEL(3, " OK \n"); - /* LZ4 streaming tests */ - { LZ4_stream_t streamingState; - U64 crcOrig; - int result; + DISPLAYLEVEL(3, "LZ4_initStream with multiple valid alignments : "); + { typedef struct { + LZ4_stream_t state1; + LZ4_stream_t state2; + char c; + LZ4_stream_t state3; + } shct; + shct* const shc = (shct*)malloc(sizeof(*shc)); + assert(shc != NULL); + memset(shc, 0, sizeof(*shc)); + DISPLAYLEVEL(4, "state1(%p) state2(%p) state3(%p) LZ4_stream_t size(0x%x): ", + &(shc->state1), &(shc->state2), &(shc->state3), (unsigned)sizeof(LZ4_stream_t)); + FUZ_CHECKTEST( LZ4_initStream(&(shc->state1), sizeof(shc->state1)) == NULL, "state1 (%p) failed init", &(shc->state1) ); + FUZ_CHECKTEST( LZ4_initStream(&(shc->state2), sizeof(shc->state2)) == NULL, "state2 (%p) failed init", &(shc->state2) ); + FUZ_CHECKTEST( LZ4_initStream(&(shc->state3), sizeof(shc->state3)) == NULL, "state3 (%p) failed init", &(shc->state3) ); + FUZ_CHECKTEST( LZ4_initStream((char*)&(shc->state1) + 1, sizeof(shc->state1)) != NULL, + "hc1+1 (%p) init must fail, due to bad alignment", (char*)&(shc->state1) + 1 ); + free(shc); + } + DISPLAYLEVEL(3, "all inits OK \n"); - /* Allocation test */ - { LZ4_stream_t* const statePtr = LZ4_createStream(); - FUZ_CHECKTEST(statePtr==NULL, "LZ4_createStream() allocation failed"); - LZ4_freeStream(statePtr); - } + /* Allocation test */ + { LZ4_stream_t* const statePtr = LZ4_createStream(); + FUZ_CHECKTEST(statePtr==NULL, "LZ4_createStream() allocation failed"); + LZ4_freeStream(statePtr); + } + + /* LZ4 streaming tests */ + { LZ4_stream_t streamingState; /* simple compression test */ - crcOrig = XXH64(testInput, testCompressedSize, 0); LZ4_initStream(&streamingState, sizeof(streamingState)); - result = LZ4_compress_fast_continue(&streamingState, testInput, testCompressed, testCompressedSize, testCompressedSize-1, 1); - FUZ_CHECKTEST(result==0, "LZ4_compress_fast_continue() compression failed!"); - FUZ_CHECKTEST(streamingState.internal_donotuse.dirty, "context should be clean") + { int const cs = LZ4_compress_fast_continue(&streamingState, testInput, testCompressed, testCompressedSize, testCompressedSize-1, 1); + FUZ_CHECKTEST(cs==0, "LZ4_compress_fast_continue() compression failed!"); + { int const r = LZ4_decompress_safe(testCompressed, testVerify, cs, testCompressedSize); + FUZ_CHECKTEST(r!=(int)testCompressedSize, "LZ4_decompress_safe() decompression failed"); + } } + { U64 const crcOrig = XXH64(testInput, testCompressedSize, 0); + U64 const crcNew = XXH64(testVerify, testCompressedSize, 0); + FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption"); + } + + /* early saveDict */ + DISPLAYLEVEL(3, "saveDict (right after init) : "); + { LZ4_stream_t* const ctx = LZ4_initStream(&streamingState, sizeof(streamingState)); + assert(ctx != NULL); /* ensure init is successful */ - result = LZ4_decompress_safe(testCompressed, testVerify, result, testCompressedSize); - FUZ_CHECKTEST(result!=(int)testCompressedSize, "LZ4_decompress_safe() decompression failed"); - { U64 const crcNew = XXH64(testVerify, testCompressedSize, 0); - FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe() decompression corruption"); } + /* Check access violation with asan */ + FUZ_CHECKTEST( LZ4_saveDict(ctx, NULL, 0) != 0, + "LZ4_saveDict() can't save anything into (NULL,0)"); + + /* Check access violation with asan */ + { char tmp_buffer[240] = { 0 }; + FUZ_CHECKTEST( LZ4_saveDict(ctx, tmp_buffer, sizeof(tmp_buffer)) != 0, + "LZ4_saveDict() can't save anything since compression hasn't started"); + } } + DISPLAYLEVEL(3, "OK \n"); /* ring buffer test */ { XXH64_state_t xxhOrig; @@ -1142,7 +1203,7 @@ static void FUZ_unitTests(int compressionLevel) LZ4_setStreamDecode(&decodeStateFast, NULL, 0); while (iNext + messageSize < testCompressedSize) { - int compressedSize; + int compressedSize; U64 crcOrig; XXH64_update(&xxhOrig, testInput + iNext, messageSize); crcOrig = XXH64_digest(&xxhOrig); @@ -1150,15 +1211,15 @@ static void FUZ_unitTests(int compressionLevel) compressedSize = LZ4_compress_fast_continue(&streamingState, ringBuffer + rNext, testCompressed, (int)messageSize, testCompressedSize-ringBufferSize, 1); FUZ_CHECKTEST(compressedSize==0, "LZ4_compress_fast_continue() compression failed"); - result = LZ4_decompress_safe_continue(&decodeStateSafe, testCompressed, testVerify + dNext, compressedSize, (int)messageSize); - FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : LZ4_decompress_safe_continue() test failed"); + { int const r = LZ4_decompress_safe_continue(&decodeStateSafe, testCompressed, testVerify + dNext, compressedSize, (int)messageSize); + FUZ_CHECKTEST(r!=(int)messageSize, "ringBuffer : LZ4_decompress_safe_continue() test failed"); } XXH64_update(&xxhNewSafe, testVerify + dNext, messageSize); { U64 const crcNew = XXH64_digest(&xxhNewSafe); FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe_continue() decompression corruption"); } - result = LZ4_decompress_fast_continue(&decodeStateFast, testCompressed, testVerify + dNext, (int)messageSize); - FUZ_CHECKTEST(result!=compressedSize, "ringBuffer : LZ4_decompress_fast_continue() test failed"); + { int const r = LZ4_decompress_fast_continue(&decodeStateFast, testCompressed, testVerify + dNext, (int)messageSize); + FUZ_CHECKTEST(r!=compressedSize, "ringBuffer : LZ4_decompress_fast_continue() test failed"); } XXH64_update(&xxhNewFast, testVerify + dNext, messageSize); { U64 const crcNew = XXH64_digest(&xxhNewFast); @@ -1171,26 +1232,45 @@ static void FUZ_unitTests(int compressionLevel) messageSize = (FUZ_rand(&randState) & maxMessageSizeMask) + 1; if (rNext + messageSize > ringBufferSize) rNext = 0; if (dNext + messageSize > dBufferSize) dNext = 0; - } - } + } } + } + + DISPLAYLEVEL(3, "LZ4_initStreamHC with multiple valid alignments : "); + { typedef struct { + LZ4_streamHC_t hc1; + LZ4_streamHC_t hc2; + char c; + LZ4_streamHC_t hc3; + } shct; + shct* const shc = (shct*)malloc(sizeof(*shc)); + assert(shc != NULL); + memset(shc, 0, sizeof(*shc)); + DISPLAYLEVEL(4, "hc1(%p) hc2(%p) hc3(%p) size(0x%x): ", + &(shc->hc1), &(shc->hc2), &(shc->hc3), (unsigned)sizeof(LZ4_streamHC_t)); + FUZ_CHECKTEST( LZ4_initStreamHC(&(shc->hc1), sizeof(shc->hc1)) == NULL, "hc1 (%p) failed init", &(shc->hc1) ); + FUZ_CHECKTEST( LZ4_initStreamHC(&(shc->hc2), sizeof(shc->hc2)) == NULL, "hc2 (%p) failed init", &(shc->hc2) ); + FUZ_CHECKTEST( LZ4_initStreamHC(&(shc->hc3), sizeof(shc->hc3)) == NULL, "hc3 (%p) failed init", &(shc->hc3) ); + FUZ_CHECKTEST( LZ4_initStreamHC((char*)&(shc->hc1) + 1, sizeof(shc->hc1)) != NULL, + "hc1+1 (%p) init must fail, due to bad alignment", (char*)&(shc->hc1) + 1 ); + free(shc); } + DISPLAYLEVEL(3, "all inits OK \n"); /* LZ4 HC streaming tests */ { LZ4_streamHC_t sHC; /* statically allocated */ - U64 crcOrig; int result; LZ4_initStreamHC(&sHC, sizeof(sHC)); /* Allocation test */ - DISPLAYLEVEL(3, " Basic HC allocation : "); + DISPLAYLEVEL(3, "Basic HC allocation : "); { LZ4_streamHC_t* const sp = LZ4_createStreamHC(); FUZ_CHECKTEST(sp==NULL, "LZ4_createStreamHC() allocation failed"); LZ4_freeStreamHC(sp); } - DISPLAYLEVEL(3, " OK \n"); + DISPLAYLEVEL(3, "OK \n"); /* simple HC compression test */ - DISPLAYLEVEL(3, " Simple HC round-trip : "); + DISPLAYLEVEL(3, "Simple HC round-trip : "); { U64 const crc64 = XXH64(testInput, testCompressedSize, 0); LZ4_setCompressionLevel(&sHC, compressionLevel); result = LZ4_compress_HC_continue(&sHC, testInput, testCompressed, testCompressedSize, testCompressedSize-1); @@ -1202,10 +1282,26 @@ static void FUZ_unitTests(int compressionLevel) { U64 const crcNew = XXH64(testVerify, testCompressedSize, 0); FUZ_CHECKTEST(crc64!=crcNew, "LZ4_decompress_safe() decompression corruption"); } } - DISPLAYLEVEL(3, " OK \n"); + DISPLAYLEVEL(3, "OK \n"); + + /* saveDictHC test #926 */ + DISPLAYLEVEL(3, "saveDictHC test #926 : "); + { LZ4_streamHC_t* const ctx = LZ4_initStreamHC(&sHC, sizeof(sHC)); + assert(ctx != NULL); /* ensure init is successful */ + + /* Check access violation with asan */ + FUZ_CHECKTEST( LZ4_saveDictHC(ctx, NULL, 0) != 0, + "LZ4_saveDictHC() can't save anything into (NULL,0)"); + + /* Check access violation with asan */ + { char tmp_buffer[240] = { 0 }; + FUZ_CHECKTEST( LZ4_saveDictHC(ctx, tmp_buffer, sizeof(tmp_buffer)) != 0, + "LZ4_saveDictHC() can't save anything since compression hasn't started"); + } } + DISPLAYLEVEL(3, "OK \n"); /* long sequence test */ - DISPLAYLEVEL(3, " Long sequence HC test : "); + DISPLAYLEVEL(3, "Long sequence HC_destSize test : "); { size_t const blockSize = 1 MB; size_t const targetSize = 4116; /* size carefully selected to trigger an overflow */ void* const block = malloc(blockSize); @@ -1223,8 +1319,13 @@ static void FUZ_unitTests(int compressionLevel) assert(targetSize < INT_MAX); result = LZ4_compress_HC_destSize(&sHC, (const char*)block, (char*)dstBlock, &srcSize, (int)targetSize, 3); DISPLAYLEVEL(4, "cSize=%i; readSize=%i; ", result, srcSize); - FUZ_CHECKTEST(result!=4116, "LZ4_compress_HC_destSize() : compression must fill dstBuffer completely, but no more !"); - FUZ_CHECKTEST(((char*)dstBlock)[targetSize] != sentinel, "LZ4_compress_HC_destSize()") + FUZ_CHECKTEST(result != 4116, "LZ4_compress_HC_destSize() : " + "compression (%i->%i) must fill dstBuffer (%i) exactly", + srcSize, result, (int)targetSize); + FUZ_CHECKTEST(((char*)dstBlock)[targetSize] != sentinel, + "LZ4_compress_HC_destSize() overwrites dst buffer"); + FUZ_CHECKTEST(srcSize < 1045000, "LZ4_compress_HC_destSize() doesn't compress enough" + " (%i -> %i , expected > %i)", srcSize, result, 1045000); LZ4_resetStreamHC_fast(&sHC, 3); /* make sure the context is clean after the test */ free(block); @@ -1233,7 +1334,7 @@ static void FUZ_unitTests(int compressionLevel) DISPLAYLEVEL(3, " OK \n"); /* simple dictionary HC compression test */ - DISPLAYLEVEL(3, " HC dictionary compression test : "); + DISPLAYLEVEL(3, "HC dictionary compression test : "); { U64 const crc64 = XXH64(testInput + 64 KB, testCompressedSize, 0); LZ4_resetStreamHC_fast(&sHC, compressionLevel); LZ4_loadDictHC(&sHC, testInput, 64 KB); @@ -1302,6 +1403,7 @@ static void FUZ_unitTests(int compressionLevel) XXH64_reset(&crcNewState, 0); while (segStart + segSize < testInputSize) { + XXH64_hash_t crcOrig; XXH64_update(&crcOrigState, testInput + segStart, segSize); crcOrig = XXH64_digest(&crcOrigState); assert(segSize <= INT_MAX); @@ -1348,6 +1450,7 @@ static void FUZ_unitTests(int compressionLevel) while (iNext + messageSize < testCompressedSize) { int compressedSize; + XXH64_hash_t crcOrig; XXH64_update(&xxhOrig, testInput + iNext, messageSize); crcOrig = XXH64_digest(&xxhOrig); @@ -1362,7 +1465,7 @@ static void FUZ_unitTests(int compressionLevel) FUZ_CHECKTEST(result!=(int)messageSize, "ringBuffer : LZ4_decompress_safe_continue() test failed"); XXH64_update(&xxhNewSafe, testVerify + dNext, messageSize); - { U64 const crcNew = XXH64_digest(&xxhNewSafe); + { XXH64_hash_t const crcNew = XXH64_digest(&xxhNewSafe); FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_safe_continue() decompression corruption"); } assert(messageSize < INT_MAX); @@ -1370,7 +1473,7 @@ static void FUZ_unitTests(int compressionLevel) FUZ_CHECKTEST(result!=compressedSize, "ringBuffer : LZ4_decompress_fast_continue() test failed"); XXH64_update(&xxhNewFast, testVerify + dNext, messageSize); - { U64 const crcNew = XXH64_digest(&xxhNewFast); + { XXH64_hash_t const crcNew = XXH64_digest(&xxhNewFast); FUZ_CHECKTEST(crcOrig!=crcNew, "LZ4_decompress_fast_continue() decompression corruption"); } /* prepare next message */ @@ -1391,6 +1494,7 @@ static void FUZ_unitTests(int compressionLevel) */ { XXH64_state_t xxhOrig; XXH64_state_t xxhNewSafe, xxhNewFast; + XXH64_hash_t crcOrig; LZ4_streamDecode_t decodeStateSafe, decodeStateFast; const int maxMessageSizeLog = 12; const int maxMessageSize = 1 << maxMessageSizeLog; @@ -1487,8 +1591,87 @@ static void FUZ_unitTests(int compressionLevel) iNext = (FUZ_rand(&randState) & 65535); if (dNext + maxMessageSize > dBufferSize) dNext = 0; } + } /* Ring buffer test : Non synchronized decoder */ + } + + DISPLAYLEVEL(3, "LZ4_compress_HC_destSize : "); + /* encode congenerical sequence test for HC compressors */ + { LZ4_streamHC_t* const sHC = LZ4_createStreamHC(); + int const src_buf_size = 3 MB; + int const dst_buf_size = 6 KB; + int const payload = 0; + int const dst_step = 43; + int const dst_min_len = 33 + (FUZ_rand(&randState) % dst_step); + int const dst_max_len = 5000; + int slen, dlen; + char* sbuf1 = (char*)malloc(src_buf_size + 1); + char* sbuf2 = (char*)malloc(src_buf_size + 1); + char* dbuf1 = (char*)malloc(dst_buf_size + 1); + char* dbuf2 = (char*)malloc(dst_buf_size + 1); + + assert(sHC != NULL); + assert(dst_buf_size > dst_max_len); + if (!sbuf1 || !sbuf2 || !dbuf1 || !dbuf2) { + EXIT_MSG("not enough memory for FUZ_unitTests (destSize)"); + } + for (dlen = dst_min_len; dlen <= dst_max_len; dlen += dst_step) { + int src_len = (dlen - 10)*255 + 24; + if (src_len + 10 >= src_buf_size) break; /* END of check */ + for (slen = src_len - 3; slen <= src_len + 3; slen++) { + int srcsz1, srcsz2; + int dsz1, dsz2; + int res1, res2; + char const endchk = (char)0x88; + DISPLAYLEVEL(5, "slen = %i, ", slen); + + srcsz1 = slen; + memset(sbuf1, payload, slen); + memset(dbuf1, 0, dlen); + dbuf1[dlen] = endchk; + dsz1 = LZ4_compress_destSize(sbuf1, dbuf1, &srcsz1, dlen); + DISPLAYLEVEL(5, "LZ4_compress_destSize: %i bytes compressed into %i bytes, ", srcsz1, dsz1); + DISPLAYLEVEL(5, "last token : 0x%0X, ", dbuf1[dsz1 - 6]); + DISPLAYLEVEL(5, "last ML extra lenbyte : 0x%0X, \n", dbuf1[dsz1 - 7]); + FUZ_CHECKTEST(dbuf1[dlen] != endchk, "LZ4_compress_destSize() overwrite dst buffer !"); + FUZ_CHECKTEST(dsz1 <= 0, "LZ4_compress_destSize() compression failed"); + FUZ_CHECKTEST(dsz1 > dlen, "LZ4_compress_destSize() result larger than dst buffer !"); + FUZ_CHECKTEST(srcsz1 > slen, "LZ4_compress_destSize() read more than src buffer !"); + + res1 = LZ4_decompress_safe(dbuf1, sbuf1, dsz1, src_buf_size); + FUZ_CHECKTEST(res1 != srcsz1, "LZ4_compress_destSize() decompression failed!"); + + srcsz2 = slen; + memset(sbuf2, payload, slen); + memset(dbuf2, 0, dlen); + dbuf2[dlen] = endchk; + LZ4_resetStreamHC(sHC, compressionLevel); + dsz2 = LZ4_compress_HC_destSize(sHC, sbuf2, dbuf2, &srcsz2, dlen, compressionLevel); + DISPLAYLEVEL(5, "LZ4_compress_HC_destSize: %i bytes compressed into %i bytes, ", srcsz2, dsz2); + DISPLAYLEVEL(5, "last token : 0x%0X, ", dbuf2[dsz2 - 6]); + DISPLAYLEVEL(5, "last ML extra lenbyte : 0x%0X, \n", dbuf2[dsz2 - 7]); + FUZ_CHECKTEST(dbuf2[dlen] != endchk, "LZ4_compress_HC_destSize() overwrite dst buffer !"); + FUZ_CHECKTEST(dsz2 <= 0, "LZ4_compress_HC_destSize() compression failed"); + FUZ_CHECKTEST(dsz2 > dlen, "LZ4_compress_HC_destSize() result larger than dst buffer !"); + FUZ_CHECKTEST(srcsz2 > slen, "LZ4_compress_HC_destSize() read more than src buffer !"); + FUZ_CHECKTEST(dsz2 != dsz1, "LZ4_compress_HC_destSize() return incorrect result !"); + FUZ_CHECKTEST(srcsz2 != srcsz1, "LZ4_compress_HC_destSize() return incorrect src buffer size " + ": srcsz2(%i) != srcsz1(%i)", srcsz2, srcsz1); + FUZ_CHECKTEST(memcmp(dbuf2, dbuf1, (size_t)dsz2), "LZ4_compress_HC_destSize() return incorrect data into dst buffer !"); + + res2 = LZ4_decompress_safe(dbuf2, sbuf1, dsz2, src_buf_size); + FUZ_CHECKTEST(res2 != srcsz1, "LZ4_compress_HC_destSize() decompression failed!"); + + FUZ_CHECKTEST(memcmp(sbuf1, sbuf2, (size_t)res2), "LZ4_compress_HC_destSize() decompression corruption!"); + } } + LZ4_freeStreamHC(sHC); + free(sbuf1); + free(sbuf2); + free(dbuf1); + free(dbuf2); } + DISPLAYLEVEL(3, " OK \n"); + /* clean up */ free(testInput); |