diff options
author | Yann Collet <Cyan4973@users.noreply.github.com> | 2022-06-12 20:52:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-12 20:52:02 (GMT) |
commit | 4ebe313e00aa52c837ee029ede39a0503a8a39c9 (patch) | |
tree | 27a9f6692067f317d0353a3b34b90e8132c14b24 | |
parent | 97d60acd89addfea059e91dec132f283c699c4b6 (diff) | |
parent | 582f5fe534675da1cff232b77970208b6fc240f8 (diff) | |
download | lz4-4ebe313e00aa52c837ee029ede39a0503a8a39c9.zip lz4-4ebe313e00aa52c837ee029ede39a0503a8a39c9.tar.gz lz4-4ebe313e00aa52c837ee029ede39a0503a8a39c9.tar.bz2 |
Merge pull request #1093 from yawqi/partial-with-dict
API: add `LZ4_decompress_safe_partial_usingDict` to support partial decompression with dict
-rw-r--r-- | examples/compress_functions.c | 2 | ||||
-rw-r--r-- | examples/simple_buffer.c | 2 | ||||
-rw-r--r-- | examples/streaming_api_basics.md | 2 | ||||
-rw-r--r-- | lib/lz4.c | 49 | ||||
-rw-r--r-- | lib/lz4.h | 1 | ||||
-rw-r--r-- | ossfuzz/decompress_fuzzer.c | 18 | ||||
-rw-r--r-- | ossfuzz/round_trip_fuzzer.c | 65 | ||||
-rw-r--r-- | tests/.gitignore | 2 | ||||
-rw-r--r-- | tests/Makefile | 7 | ||||
-rw-r--r-- | tests/decompress-partial-usingDict.c | 88 | ||||
-rw-r--r-- | tests/fullbench.c | 39 | ||||
-rw-r--r-- | tests/fuzzer.c | 40 |
12 files changed, 299 insertions, 16 deletions
diff --git a/examples/compress_functions.c b/examples/compress_functions.c index e27c612..2a9d124 100644 --- a/examples/compress_functions.c +++ b/examples/compress_functions.c @@ -48,7 +48,7 @@ * Special Note About Decompression: * Using the LZ4_decompress_safe() function protects against malicious (user) input. If you are using data from a * trusted source, or if your program is the producer (P) as well as its consumer (C) in a PC or MPMC setup, you can - * safely use the LZ4_decompress_fast function + * safely use the LZ4_decompress_fast function. */ /* Since lz4 compiles with c99 and not gnu/std99 we need to enable POSIX linking for time.h structs and functions. */ diff --git a/examples/simple_buffer.c b/examples/simple_buffer.c index c7d59e3..f5c6eb2 100644 --- a/examples/simple_buffer.c +++ b/examples/simple_buffer.c @@ -47,7 +47,7 @@ int main(void) { char* compressed_data = (char*)malloc((size_t)max_dst_size); if (compressed_data == NULL) run_screaming("Failed to allocate memory for *compressed_data.", 1); - // That's all the information and preparation LZ4 needs to compress *src into *compressed_data. + // That's all the information and preparation LZ4 needs to compress *src into* compressed_data. // Invoke LZ4_compress_default now with our size values and pointers to our memory locations. // Save the return value for error checking. const int compressed_data_size = LZ4_compress_default(src, compressed_data, src_size, max_dst_size); diff --git a/examples/streaming_api_basics.md b/examples/streaming_api_basics.md index 1ccc6e3..abffaef 100644 --- a/examples/streaming_api_basics.md +++ b/examples/streaming_api_basics.md @@ -22,7 +22,7 @@ But if you want to write advanced application, it's time to use Block or Streami Block API (de)compresses a single contiguous memory block. In other words, LZ4 library finds redundancy from a single contiguous memory block. Streaming API does same thing but (de)compresses multiple adjacent contiguous memory blocks. -So LZ4 library could find more redundancy than Block API. +So Streaming API could find more redundancy than Block API. The following figure shows difference between API and block sizes. In these figures, the original data is split into 4KiBytes contiguous chunks. @@ -700,7 +700,9 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize); - +int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, + int compressedSize, int targetOutputSize, int dstCapacity, + const void* dictStart, size_t dictSize); #if defined (__cplusplus) } #endif @@ -2228,6 +2230,15 @@ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compre (BYTE*)dest - 64 KB, NULL, 0); } +LZ4_FORCE_O2 +static int LZ4_decompress_safe_partial_withPrefix64k(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + endOnInputSize, partial_decode, withPrefix64k, + (BYTE*)dest - 64 KB, NULL, 0); +} + /* Another obsolete API function, paired with the previous one. */ int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { @@ -2246,6 +2257,16 @@ static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, i } LZ4_FORCE_O2 +static int LZ4_decompress_safe_partial_withSmallPrefix(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, + size_t prefixSize) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + endOnInputSize, partial_decode, noDict, + (BYTE*)dest-prefixSize, NULL, 0); +} + +LZ4_FORCE_O2 int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize) @@ -2256,6 +2277,17 @@ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, } LZ4_FORCE_O2 +int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, + int compressedSize, int targetOutputSize, int dstCapacity, + const void* dictStart, size_t dictSize) +{ + dstCapacity = MIN(targetOutputSize, dstCapacity); + return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, + endOnInputSize, partial_decode, usingExtDict, + (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + +LZ4_FORCE_O2 static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize, const void* dictStart, size_t dictSize) { @@ -2447,6 +2479,21 @@ int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressed return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize); } +int LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity); + if (dictStart+dictSize == dest) { + if (dictSize >= 64 KB - 1) { + return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize); +} + int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { if (dictSize==0 || dictStart+dictSize == dest) @@ -430,6 +430,7 @@ LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecod */ LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize); +LZ4LIB_API int LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxOutputSize, const char* dictStart, int dictSize); #endif /* LZ4_H_2983827168210 */ diff --git a/ossfuzz/decompress_fuzzer.c b/ossfuzz/decompress_fuzzer.c index a9a197c..490b3fd 100644 --- a/ossfuzz/decompress_fuzzer.c +++ b/ossfuzz/decompress_fuzzer.c @@ -49,11 +49,27 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) LZ4_decompress_safe_usingDict((char const*)dataAfterDict, dst, size, dstCapacity, smallDict, smallDictSize); /* Large prefix. */ - LZ4_decompress_safe_usingDict((char const*)data, dst, size, + LZ4_decompress_safe_usingDict((char const*)dataAfterDict, dst, size, dstCapacity, largeDict, largeDictSize); /* Partial decompression. */ LZ4_decompress_safe_partial((char const*)data, dst, size, dstCapacity, dstCapacity); + /* Partial decompression using each possible dictionary configuration. */ + /* Partial decompression with no dictionary. */ + LZ4_decompress_safe_partial_usingDict((char const*)data, dst, size, + dstCapacity, dstCapacity, NULL, 0); + /* Partial decompression with small external dictionary. */ + LZ4_decompress_safe_partial_usingDict((char const*)data, dst, size, + dstCapacity, dstCapacity, smallDict, smallDictSize); + /* Partial decompression with large external dictionary. */ + LZ4_decompress_safe_partial_usingDict((char const*)data, dst, size, + dstCapacity, dstCapacity, largeDict, largeDictSize); + /* Partial decompression with small prefix. */ + LZ4_decompress_safe_partial_usingDict((char const*)dataAfterDict, dst, size, + dstCapacity, dstCapacity, smallDict, smallDictSize); + /* Partial decompression wtih large prefix. */ + LZ4_decompress_safe_partial_usingDict((char const*)dataAfterDict, dst, size, + dstCapacity, dstCapacity, largeDict, largeDictSize); free(dst); free(dict); FUZZ_dataProducer_free(producer); diff --git a/ossfuzz/round_trip_fuzzer.c b/ossfuzz/round_trip_fuzzer.c index 6307058..7a2f768 100644 --- a/ossfuzz/round_trip_fuzzer.c +++ b/ossfuzz/round_trip_fuzzer.c @@ -20,8 +20,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) size_t const partialCapacity = FUZZ_getRange_from_uint32(partialCapacitySeed, 0, size); size_t const dstCapacity = LZ4_compressBound(size); - - char* const dst = (char*)malloc(dstCapacity); + size_t const largeSize = 64 * 1024 - 1; + size_t const smallSize = 1024; + char* const dstPlusLargePrefix = (char*)malloc(dstCapacity + largeSize); + char* const dstPlusSmallPrefix = dstPlusLargePrefix + largeSize - smallSize; + char* const largeDict = (char*)malloc(largeSize); + char* const smallDict = largeDict + largeSize - smallSize; + char* const dst = dstPlusLargePrefix + largeSize; char* const rt = (char*)malloc(size); FUZZ_ASSERT(dst); @@ -47,7 +52,61 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); free(partial); } - + /* Partial decompression using dict with no dict. */ + { + char* const partial = (char*)malloc(partialCapacity); + FUZZ_ASSERT(partial); + int const partialSize = LZ4_decompress_safe_partial_usingDict( + dst, partial, dstSize, partialCapacity, partialCapacity, NULL, 0); + FUZZ_ASSERT(partialSize >= 0); + FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); + FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); + free(partial); + } + /* Partial decompression using dict with small prefix as dict */ + { + char* const partial = (char*)malloc(partialCapacity); + FUZZ_ASSERT(partial); + int const partialSize = LZ4_decompress_safe_partial_usingDict( + dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusSmallPrefix, smallSize); + FUZZ_ASSERT(partialSize >= 0); + FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); + FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); + free(partial); + } + /* Partial decompression using dict with large prefix as dict */ + { + char* const partial = (char*)malloc(partialCapacity); + FUZZ_ASSERT(partial); + int const partialSize = LZ4_decompress_safe_partial_usingDict( + dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusLargePrefix, largeSize); + FUZZ_ASSERT(partialSize >= 0); + FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); + FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); + free(partial); + } + /* Partial decompression using dict with small external dict */ + { + char* const partial = (char*)malloc(partialCapacity); + FUZZ_ASSERT(partial); + int const partialSize = LZ4_decompress_safe_partial_usingDict( + dst, partial, dstSize, partialCapacity, partialCapacity, smallDict, smallSize); + FUZZ_ASSERT(partialSize >= 0); + FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); + FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); + free(partial); + } + /* Partial decompression using dict with large external dict */ + { + char* const partial = (char*)malloc(partialCapacity); + FUZZ_ASSERT(partial); + int const partialSize = LZ4_decompress_safe_partial_usingDict( + dst, partial, dstSize, partialCapacity, partialCapacity, largeDict, largeSize); + FUZZ_ASSERT(partialSize >= 0); + FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); + FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); + free(partial); + } free(dst); free(rt); diff --git a/tests/.gitignore b/tests/.gitignore index 99351af..346c989 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -12,7 +12,7 @@ roundTripTest checkTag checkFrame decompress-partial - +decompress-partial-usingDict # test artefacts tmp* versionsTest diff --git a/tests/Makefile b/tests/Makefile index b4d40ca..9f83f06 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -112,6 +112,9 @@ checkFrame : lz4frame.o lz4.o lz4hc.o xxhash.o checkFrame.c decompress-partial: lz4.o decompress-partial.c $(CC) $(FLAGS) $^ -o $@$(EXT) +decompress-partial-usingDict: lz4.o decompress-partial-usingDict.c + $(CC) $(FLAGS) $^ -o $@$(EXT) + .PHONY: clean clean: @$(MAKE) -C $(LZ4DIR) $@ > $(VOID) @@ -547,8 +550,10 @@ test-mem: lz4 datagen fuzzer frametest fullbench test-mem32: lz4c32 datagen # unfortunately, valgrind doesn't seem to work with non-native binary... -test-decompress-partial : decompress-partial +test-decompress-partial : decompress-partial decompress-partial-usingDict @echo "\n ---- test decompress-partial ----" ./decompress-partial$(EXT) + @echo "\n ---- test decompress-partial-usingDict ----" + ./decompress-partial-usingDict$(EXT) endif diff --git a/tests/decompress-partial-usingDict.c b/tests/decompress-partial-usingDict.c new file mode 100644 index 0000000..cfcb971 --- /dev/null +++ b/tests/decompress-partial-usingDict.c @@ -0,0 +1,88 @@ +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "lz4.h" + +const char source[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod\n" + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim\n" + "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\n" + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate\n" + "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat\n" + "cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id\n" + "est laborum.\n" + "\n" + "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium\n" + "doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore\n" + "veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim\n" + "ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia\n" + "consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque\n" + "porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur,\n" + "adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore\n" + "et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis\n" + "nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid\n" + "ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea\n" + "voluptate velit esse quam nihil molestiae consequatur, vel illum qui\n" + "dolorem eum fugiat quo voluptas nulla pariatur?\n"; + +#define BUFFER_SIZE 2048 + +int main(void) +{ + int srcLen = (int)strlen(source); + size_t const smallSize = 1024; + size_t const largeSize = 64 * 1024 - 1; + char cmpBuffer[BUFFER_SIZE]; + char buffer[BUFFER_SIZE + largeSize]; + char* outBuffer = buffer + largeSize; + char* const dict = (char*)malloc(largeSize); + char* const largeDict = dict; + char* const smallDict = dict + largeSize - smallSize; + int cmpSize; + int i; + + cmpSize = LZ4_compress_default(source, cmpBuffer, srcLen, BUFFER_SIZE); + + for (i = cmpSize; i < cmpSize + 10; ++i) { + int result = LZ4_decompress_safe_partial_usingDict(cmpBuffer, outBuffer, i, srcLen, BUFFER_SIZE, NULL, 0); + if ((result < 0) || (result != srcLen) || memcmp(source, outBuffer, srcLen)) { + printf("test decompress-partial-usingDict with no dict error \n"); + return -1; + } + } + + for (i = cmpSize; i < cmpSize + 10; ++i) { + int result = LZ4_decompress_safe_partial_usingDict(cmpBuffer, outBuffer, i, srcLen, BUFFER_SIZE, outBuffer - smallSize, smallSize); + if ((result < 0) || (result != srcLen) || memcmp(source, outBuffer, srcLen)) { + printf("test decompress-partial-usingDict with small prefix error \n"); + return -1; + } + } + + for (i = cmpSize; i < cmpSize + 10; ++i) { + int result = LZ4_decompress_safe_partial_usingDict(cmpBuffer, outBuffer, i, srcLen, BUFFER_SIZE, buffer, largeSize); + if ((result < 0) || (result != srcLen) || memcmp(source, outBuffer, srcLen)) { + printf("test decompress-partial-usingDict with large prefix error \n"); + return -1; + } + } + + for (i = cmpSize; i < cmpSize + 10; ++i) { + int result = LZ4_decompress_safe_partial_usingDict(cmpBuffer, outBuffer, i, srcLen, BUFFER_SIZE, smallDict, smallSize); + if ((result < 0) || (result != srcLen) || memcmp(source, outBuffer, srcLen)) { + printf("test decompress-partial-usingDict with small external dict error \n"); + return -1; + } + } + + for (i = cmpSize; i < cmpSize + 10; ++i) { + int result = LZ4_decompress_safe_partial_usingDict(cmpBuffer, outBuffer, i, srcLen, BUFFER_SIZE, largeDict, largeSize); + if ((result < 0) || (result != srcLen) || memcmp(source, outBuffer, srcLen)) { + printf("test decompress-partial-usingDict with large external dict error \n"); + return -1; + } + } + + printf("test decompress-partial-usingDict OK \n"); + return 0; +} diff --git a/tests/fullbench.c b/tests/fullbench.c index 55bf0b7..ec20dcb 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -312,6 +312,13 @@ static int local_LZ4_decompress_safe_usingDict(const char* in, char* out, int in return outSize; } +static int local_LZ4_decompress_safe_partial_usingDict(const char* in, char* out, int inSize, int outSize) +{ + int result = LZ4_decompress_safe_partial_usingDict(in, out, inSize, outSize - 5, outSize, out - 65536, 65536); + if (result < 0) return result; + return outSize; +} + #ifndef LZ4_DLL_IMPORT #if defined (__cplusplus) extern "C" { @@ -325,12 +332,30 @@ extern int LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSiz static int local_LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize) { - (void)inSize; LZ4_decompress_safe_forceExtDict(in, out, inSize, outSize, out - 65536, 65536); return outSize; } #endif +#ifndef LZ4_DLL_IMPORT +#if defined (__cplusplus) +extern "C" { +#endif + +extern int LZ4_decompress_safe_partial_forceExtDict(const char* in, char* out, int inSize, int targetOutputSize, int dstCapacity, const void* dict, size_t dictSize); + +#if defined (__cplusplus) +} +#endif + +static int local_LZ4_decompress_safe_partial_forceExtDict(const char* in, char* out, int inSize, int outSize) +{ + int result = LZ4_decompress_safe_partial_forceExtDict(in, out, inSize, outSize - 5, outSize, out - 65536, 65536); + if (result < 0) return result; + return outSize; +} +#endif + static int local_LZ4_decompress_safe_partial(const char* in, char* out, int inSize, int outSize) { int result = LZ4_decompress_safe_partial(in, out, inSize, outSize - 5, outSize); @@ -657,15 +682,17 @@ int fullSpeedBench(const char** fileNamesTable, int nbFiles) case 5: decompressionFunction = local_LZ4_decompress_safe_withPrefix64k; dName = "LZ4_decompress_safe_withPrefix64k"; break; case 6: decompressionFunction = local_LZ4_decompress_safe_usingDict; dName = "LZ4_decompress_safe_usingDict"; break; case 7: decompressionFunction = local_LZ4_decompress_safe_partial; dName = "LZ4_decompress_safe_partial"; checkResult = 0; break; + case 8: decompressionFunction = local_LZ4_decompress_safe_partial_usingDict; dName = "LZ4_decompress_safe_partial_usingDict"; checkResult = 0; break; #ifndef LZ4_DLL_IMPORT - case 8: decompressionFunction = local_LZ4_decompress_safe_forceExtDict; dName = "LZ4_decompress_safe_forceExtDict"; break; + case 9: decompressionFunction = local_LZ4_decompress_safe_partial_forceExtDict; dName = "LZ4_decompress_safe_partial_forceExtDict"; checkResult = 0; break; + case 10: decompressionFunction = local_LZ4_decompress_safe_forceExtDict; dName = "LZ4_decompress_safe_forceExtDict"; break; #endif - case 10: case 11: case 12: - if (dAlgNb == 10) { decompressionFunction = local_LZ4F_decompress; dName = "LZ4F_decompress"; } /* can be skipped */ - if (dAlgNb == 11) { decompressionFunction = local_LZ4F_decompress_followHint; dName = "LZ4F_decompress_followHint"; } /* can be skipped */ - if (dAlgNb == 12) { decompressionFunction = local_LZ4F_decompress_noHint; dName = "LZ4F_decompress_noHint"; } /* can be skipped */ + case 13: + if (dAlgNb == 11) { decompressionFunction = local_LZ4F_decompress; dName = "LZ4F_decompress"; } /* can be skipped */ + if (dAlgNb == 12) { decompressionFunction = local_LZ4F_decompress_followHint; dName = "LZ4F_decompress_followHint"; } /* can be skipped */ + if (dAlgNb == 13) { decompressionFunction = local_LZ4F_decompress_noHint; dName = "LZ4F_decompress_noHint"; } /* can be skipped */ /* prepare compressed data using frame format */ { size_t const fcsize = LZ4F_compressFrame(compressed_buff, (size_t)compressedBuffSize, orig_buff, benchedSize, NULL); assert(!LZ4F_isError(fcsize)); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index e6fa13c..07d63a2 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -630,6 +630,46 @@ static int FUZ_test(U32 seed, U32 nbCycles, const U32 startCycle, const double c FUZ_CHECKTEST(memcmp(block, decodedBuffer, (size_t)targetSize), "LZ4_decompress_safe_partial: corruption detected in regenerated data"); } + /* Partial decompression using dictionary. */ + FUZ_DISPLAYTEST("test LZ4_decompress_safe_partial_usingDict using no dict"); + { 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_usingDict(compressedBuffer, decodedBuffer, inCSize, targetSize, blockSize, NULL, 0); + FUZ_CHECKTEST(decResult<0, "LZ4_decompress_safe_partial_usingDict failed despite valid input data (error:%i)", decResult); + FUZ_CHECKTEST(decResult != targetSize, "LZ4_decompress_safe_partial_usingDict did not regenerated required amount of data (%i < %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(decodedBuffer[targetSize] != sentinel, "LZ4_decompress_safe_partial_usingDict overwrite beyond requested size (though %i <= %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(memcmp(block, decodedBuffer, (size_t)targetSize), "LZ4_decompress_safe_partial_usingDict: corruption detected in regenerated data"); + } + + FUZ_DISPLAYTEST("test LZ4_decompress_safe_partial_usingDict() using prefix as dict"); + { 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_usingDict(compressedBuffer, decodedBuffer, inCSize, targetSize, blockSize, decodedBuffer, dictSize); + FUZ_CHECKTEST(decResult<0, "LZ4_decompress_safe_partial_usingDict failed despite valid input data (error:%i)", decResult); + FUZ_CHECKTEST(decResult != targetSize, "LZ4_decompress_safe_partial_usingDict did not regenerated required amount of data (%i < %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(decodedBuffer[targetSize] != sentinel, "LZ4_decompress_safe_partial_usingDict overwrite beyond requested size (though %i <= %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(memcmp(block, decodedBuffer, (size_t)targetSize), "LZ4_decompress_safe_partial_usingDict: corruption detected in regenerated data"); + } + + FUZ_DISPLAYTEST("test LZ4_decompress_safe_partial_usingDict() using external dict"); + { 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_usingDict(compressedBuffer, decodedBuffer, inCSize, targetSize, blockSize, dict, dictSize); + FUZ_CHECKTEST(decResult<0, "LZ4_decompress_safe_partial_usingDict failed despite valid input data (error:%i)", decResult); + FUZ_CHECKTEST(decResult != targetSize, "LZ4_decompress_safe_partial_usingDict did not regenerated required amount of data (%i < %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(decodedBuffer[targetSize] != sentinel, "LZ4_decompress_safe_partial_usingDict overwrite beyond requested size (though %i <= %i <= %i)", decResult, targetSize, blockSize); + FUZ_CHECKTEST(memcmp(block, decodedBuffer, (size_t)targetSize), "LZ4_decompress_safe_partial_usingDict: corruption detected in regenerated data"); + } + /* Test Compression with limited output size */ /* Test compression with output size being exactly what's necessary (should work) */ |