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
15int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
16{
17    FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size);
18    size_t const partialCapacitySeed = FUZZ_dataProducer_retrieve32(producer);
19    size = FUZZ_dataProducer_remainingBytes(producer);
20
21    size_t const partialCapacity = FUZZ_getRange_from_uint32(partialCapacitySeed, 0, size);
22    size_t const dstCapacity = LZ4_compressBound(size);
23    size_t const largeSize = 64 * 1024 - 1;
24    size_t const smallSize = 1024;
25    char* const dstPlusLargePrefix = (char*)malloc(dstCapacity + largeSize);
26    FUZZ_ASSERT(dstPlusLargePrefix);
27    char* const dstPlusSmallPrefix = dstPlusLargePrefix + largeSize - smallSize;
28    char* const largeDict = (char*)malloc(largeSize);
29    FUZZ_ASSERT(largeDict);
30    char* const smallDict = largeDict + largeSize - smallSize;
31    char* const dst = dstPlusLargePrefix + largeSize;
32    char* const rt = (char*)malloc(size);
33    FUZZ_ASSERT(rt);
34
35    /* Compression must succeed and round trip correctly. */
36    int const dstSize = LZ4_compress_default((const char*)data, dst,
37                                             size, dstCapacity);
38    FUZZ_ASSERT(dstSize > 0);
39
40    int const rtSize = LZ4_decompress_safe(dst, rt, dstSize, size);
41    FUZZ_ASSERT_MSG(rtSize == size, "Incorrect size");
42    FUZZ_ASSERT_MSG(!memcmp(data, rt, size), "Corruption!");
43
44    /* Partial decompression must succeed. */
45    {
46        char* const partial = (char*)malloc(partialCapacity);
47        FUZZ_ASSERT(partial);
48        int const partialSize = LZ4_decompress_safe_partial(
49                dst, partial, dstSize, partialCapacity, partialCapacity);
50        FUZZ_ASSERT(partialSize >= 0);
51        FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
52        FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
53        free(partial);
54    }
55    /* Partial decompression using dict with no dict. */
56    {
57        char* const partial = (char*)malloc(partialCapacity);
58        FUZZ_ASSERT(partial);
59        int const partialSize = LZ4_decompress_safe_partial_usingDict(
60                dst, partial, dstSize, partialCapacity, partialCapacity, NULL, 0);
61        FUZZ_ASSERT(partialSize >= 0);
62        FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
63        FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
64        free(partial);
65    }
66    /* Partial decompression using dict with small prefix as dict */
67    {
68        char* const partial = (char*)malloc(partialCapacity);
69        FUZZ_ASSERT(partial);
70        int const partialSize = LZ4_decompress_safe_partial_usingDict(
71                dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusSmallPrefix, smallSize);
72        FUZZ_ASSERT(partialSize >= 0);
73        FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
74        FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
75        free(partial);
76    }
77    /* Partial decompression using dict with large prefix as dict */
78    {
79        char* const partial = (char*)malloc(partialCapacity);
80        FUZZ_ASSERT(partial);
81        int const partialSize = LZ4_decompress_safe_partial_usingDict(
82                dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusLargePrefix, largeSize);
83        FUZZ_ASSERT(partialSize >= 0);
84        FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
85        FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
86        free(partial);
87    }
88    /* Partial decompression using dict with small external dict */
89    {
90        char* const partial = (char*)malloc(partialCapacity);
91        FUZZ_ASSERT(partial);
92        int const partialSize = LZ4_decompress_safe_partial_usingDict(
93                dst, partial, dstSize, partialCapacity, partialCapacity, smallDict, smallSize);
94        FUZZ_ASSERT(partialSize >= 0);
95        FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
96        FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
97        free(partial);
98    }
99    /* Partial decompression using dict with large external dict */
100    {
101        char* const partial = (char*)malloc(partialCapacity);
102        FUZZ_ASSERT(partial);
103        int const partialSize = LZ4_decompress_safe_partial_usingDict(
104                dst, partial, dstSize, partialCapacity, partialCapacity, largeDict, largeSize);
105        FUZZ_ASSERT(partialSize >= 0);
106        FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
107        FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
108        free(partial);
109    }
110
111    free(dstPlusLargePrefix);
112    free(largeDict);
113    free(rt);
114    FUZZ_dataProducer_free(producer);
115
116    return 0;
117}
118