2
* This fuzz target performs a lz4 round-trip test (compress & decompress),
3
* compares the result with the original, and calls abort() on corruption.
11
#include "fuzz_data_producer.h"
12
#include "fuzz_helpers.h"
14
#include "lz4_helpers.h"
16
#include "lz4frame_static.h"
18
static void decompress(LZ4F_dctx *dctx, void *src, void *dst,
19
size_t dstCapacity, size_t readSize) {
21
const void *srcPtr = (const char *) src;
22
void *dstPtr = (char *) dst;
23
const void *const srcEnd = (const char *) srcPtr + readSize;
26
while (srcPtr < srcEnd && ret != 0) {
27
/* Any data within dst has been flushed at this stage */
28
size_t dstSize = dstCapacity;
29
size_t srcSize = (const char *) srcEnd - (const char *) srcPtr;
30
ret = LZ4F_decompress(dctx, dstPtr, &dstSize, srcPtr, &srcSize,
31
/* LZ4F_decompressOptions_t */ NULL);
32
FUZZ_ASSERT(!LZ4F_isError(ret));
35
srcPtr = (const char *) srcPtr + srcSize;
36
dstPtr = (char *) dstPtr + dstSize;
39
FUZZ_ASSERT(srcPtr <= srcEnd);
43
static void compress_round_trip(const uint8_t *data, size_t size,
44
FUZZ_dataProducer_t *producer, LZ4F_preferences_t const prefs) {
46
// Choose random uncompressed offset start and end by producing seeds from random data, calculate the remaining
47
// data size that will be used for compression later and use the seeds to actually calculate the offsets
48
size_t const uncompressedOffsetSeed = FUZZ_dataProducer_retrieve32(producer);
49
size_t const uncompressedEndOffsetSeed = FUZZ_dataProducer_retrieve32(producer);
50
size = FUZZ_dataProducer_remainingBytes(producer);
52
size_t const uncompressedOffset = FUZZ_getRange_from_uint32(uncompressedOffsetSeed, 0, size);
53
size_t const uncompressedEndOffset = FUZZ_getRange_from_uint32(uncompressedEndOffsetSeed, uncompressedOffset, size);
54
size_t const uncompressedSize = uncompressedEndOffset - uncompressedOffset;
55
FUZZ_ASSERT(uncompressedOffset <= uncompressedEndOffset);
56
FUZZ_ASSERT(uncompressedEndOffset <= size);
58
const uint8_t *const uncompressedData = data + uncompressedOffset;
60
size_t const dstCapacity =
61
LZ4F_compressFrameBound(LZ4_compressBound(size), &prefs) +
63
char *const dst = (char *) malloc(dstCapacity);
64
size_t rtCapacity = dstCapacity;
65
char *const rt = (char *) malloc(rtCapacity);
70
/* Compression must succeed and round trip correctly. */
71
LZ4F_compressionContext_t ctx;
72
size_t const ctxCreation = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
73
FUZZ_ASSERT(!LZ4F_isError(ctxCreation));
75
size_t const headerSize = LZ4F_compressBegin(ctx, dst, dstCapacity, &prefs);
76
FUZZ_ASSERT(!LZ4F_isError(headerSize));
77
size_t compressedSize = headerSize;
79
/* Compress data before uncompressed offset */
80
size_t lz4Return = LZ4F_compressUpdate(ctx, dst + compressedSize, dstCapacity,
81
data, uncompressedOffset, NULL);
82
FUZZ_ASSERT(!LZ4F_isError(lz4Return));
83
compressedSize += lz4Return;
85
/* Add uncompressed data */
86
lz4Return = LZ4F_uncompressedUpdate(ctx, dst + compressedSize, dstCapacity,
87
uncompressedData, uncompressedSize, NULL);
88
FUZZ_ASSERT(!LZ4F_isError(lz4Return));
89
compressedSize += lz4Return;
91
/* Compress data after uncompressed offset */
92
lz4Return = LZ4F_compressUpdate(ctx, dst + compressedSize, dstCapacity,
93
data + uncompressedEndOffset,
94
size - uncompressedEndOffset, NULL);
95
FUZZ_ASSERT(!LZ4F_isError(lz4Return));
96
compressedSize += lz4Return;
98
/* Finish compression */
99
lz4Return = LZ4F_compressEnd(ctx, dst + compressedSize, dstCapacity, NULL);
100
FUZZ_ASSERT(!LZ4F_isError(lz4Return));
101
compressedSize += lz4Return;
103
LZ4F_decompressOptions_t opts;
104
memset(&opts, 0, sizeof(opts));
107
LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
110
decompress(dctx, dst, rt, rtCapacity, compressedSize);
112
LZ4F_freeDecompressionContext(dctx);
114
FUZZ_ASSERT_MSG(!memcmp(data, rt, size), "Corruption!");
119
FUZZ_dataProducer_free(producer);
120
LZ4F_freeCompressionContext(ctx);
123
static void compress_independent_block_mode(const uint8_t *data, size_t size) {
124
FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size);
125
LZ4F_preferences_t prefs = FUZZ_dataProducer_preferences(producer);
126
prefs.frameInfo.blockMode = LZ4F_blockIndependent;
127
compress_round_trip(data, size, producer, prefs);
131
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
132
compress_independent_block_mode(data, size);