/src/lz4/ossfuzz/round_trip_fuzzer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * This fuzz target performs a lz4 round-trip test (compress & decompress), |
3 | | * compares the result with the original, and calls abort() on corruption. |
4 | | */ |
5 | | |
6 | | #include <stddef.h> |
7 | | #include <stdint.h> |
8 | | #include <stdlib.h> |
9 | | #include <string.h> |
10 | | |
11 | | #include "fuzz_helpers.h" |
12 | | #include "lz4.h" |
13 | | #include "fuzz_data_producer.h" |
14 | | |
15 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
16 | 1.78k | { |
17 | 1.78k | FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); |
18 | 1.78k | size_t const partialCapacitySeed = FUZZ_dataProducer_retrieve32(producer); |
19 | 1.78k | size = FUZZ_dataProducer_remainingBytes(producer); |
20 | | |
21 | 1.78k | size_t const partialCapacity = FUZZ_getRange_from_uint32(partialCapacitySeed, 0, size); |
22 | 1.78k | size_t const dstCapacity = LZ4_compressBound(size); |
23 | 1.78k | size_t const largeSize = 64 * 1024 - 1; |
24 | 1.78k | size_t const smallSize = 1024; |
25 | 1.78k | char* const dstPlusLargePrefix = (char*)malloc(dstCapacity + largeSize); |
26 | 1.78k | FUZZ_ASSERT(dstPlusLargePrefix); |
27 | 1.78k | char* const dstPlusSmallPrefix = dstPlusLargePrefix + largeSize - smallSize; |
28 | 1.78k | char* const largeDict = (char*)malloc(largeSize); |
29 | 1.78k | FUZZ_ASSERT(largeDict); |
30 | 1.78k | char* const smallDict = largeDict + largeSize - smallSize; |
31 | 1.78k | char* const dst = dstPlusLargePrefix + largeSize; |
32 | 1.78k | char* const rt = (char*)malloc(size); |
33 | 1.78k | FUZZ_ASSERT(rt); |
34 | | |
35 | | /* Compression must succeed and round trip correctly. */ |
36 | 1.78k | int const dstSize = LZ4_compress_default((const char*)data, dst, |
37 | 1.78k | size, dstCapacity); |
38 | 1.78k | FUZZ_ASSERT(dstSize > 0); |
39 | | |
40 | 1.78k | int const rtSize = LZ4_decompress_safe(dst, rt, dstSize, size); |
41 | 1.78k | FUZZ_ASSERT_MSG(rtSize == size, "Incorrect size"); |
42 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, rt, size), "Corruption!"); |
43 | | |
44 | | /* Partial decompression must succeed. */ |
45 | 1.78k | { |
46 | 1.78k | char* const partial = (char*)malloc(partialCapacity); |
47 | 1.78k | FUZZ_ASSERT(partial); |
48 | 1.78k | int const partialSize = LZ4_decompress_safe_partial( |
49 | 1.78k | dst, partial, dstSize, partialCapacity, partialCapacity); |
50 | 1.78k | FUZZ_ASSERT(partialSize >= 0); |
51 | 1.78k | FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); |
52 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); |
53 | 1.78k | free(partial); |
54 | 1.78k | } |
55 | | /* Partial decompression using dict with no dict. */ |
56 | 0 | { |
57 | 1.78k | char* const partial = (char*)malloc(partialCapacity); |
58 | 1.78k | FUZZ_ASSERT(partial); |
59 | 1.78k | int const partialSize = LZ4_decompress_safe_partial_usingDict( |
60 | 1.78k | dst, partial, dstSize, partialCapacity, partialCapacity, NULL, 0); |
61 | 1.78k | FUZZ_ASSERT(partialSize >= 0); |
62 | 1.78k | FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); |
63 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); |
64 | 1.78k | free(partial); |
65 | 1.78k | } |
66 | | /* Partial decompression using dict with small prefix as dict */ |
67 | 0 | { |
68 | 1.78k | char* const partial = (char*)malloc(partialCapacity); |
69 | 1.78k | FUZZ_ASSERT(partial); |
70 | 1.78k | int const partialSize = LZ4_decompress_safe_partial_usingDict( |
71 | 1.78k | dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusSmallPrefix, smallSize); |
72 | 1.78k | FUZZ_ASSERT(partialSize >= 0); |
73 | 1.78k | FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); |
74 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); |
75 | 1.78k | free(partial); |
76 | 1.78k | } |
77 | | /* Partial decompression using dict with large prefix as dict */ |
78 | 0 | { |
79 | 1.78k | char* const partial = (char*)malloc(partialCapacity); |
80 | 1.78k | FUZZ_ASSERT(partial); |
81 | 1.78k | int const partialSize = LZ4_decompress_safe_partial_usingDict( |
82 | 1.78k | dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusLargePrefix, largeSize); |
83 | 1.78k | FUZZ_ASSERT(partialSize >= 0); |
84 | 1.78k | FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); |
85 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); |
86 | 1.78k | free(partial); |
87 | 1.78k | } |
88 | | /* Partial decompression using dict with small external dict */ |
89 | 0 | { |
90 | 1.78k | char* const partial = (char*)malloc(partialCapacity); |
91 | 1.78k | FUZZ_ASSERT(partial); |
92 | 1.78k | int const partialSize = LZ4_decompress_safe_partial_usingDict( |
93 | 1.78k | dst, partial, dstSize, partialCapacity, partialCapacity, smallDict, smallSize); |
94 | 1.78k | FUZZ_ASSERT(partialSize >= 0); |
95 | 1.78k | FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); |
96 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); |
97 | 1.78k | free(partial); |
98 | 1.78k | } |
99 | | /* Partial decompression using dict with large external dict */ |
100 | 0 | { |
101 | 1.78k | char* const partial = (char*)malloc(partialCapacity); |
102 | 1.78k | FUZZ_ASSERT(partial); |
103 | 1.78k | int const partialSize = LZ4_decompress_safe_partial_usingDict( |
104 | 1.78k | dst, partial, dstSize, partialCapacity, partialCapacity, largeDict, largeSize); |
105 | 1.78k | FUZZ_ASSERT(partialSize >= 0); |
106 | 1.78k | FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size"); |
107 | 1.78k | FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!"); |
108 | 1.78k | free(partial); |
109 | 1.78k | } |
110 | | |
111 | 0 | free(dstPlusLargePrefix); |
112 | 1.78k | free(largeDict); |
113 | 1.78k | free(rt); |
114 | 1.78k | FUZZ_dataProducer_free(producer); |
115 | | |
116 | 1.78k | return 0; |
117 | 1.78k | } |