aboutsummaryrefslogtreecommitdiff
path: root/ossfuzz/round_trip_stream_fuzzer.c
diff options
context:
space:
mode:
authorNick Terrell <terrelln@fb.com>2019-07-17 18:31:44 -0700
committerNick Terrell <terrelln@fb.com>2019-07-18 12:29:15 -0700
commit675ef9a9fc9899667d0fe9b7b2a66e402e870a6d (patch)
treec078d8a714009521b976ff07bbf77802f48e5c86 /ossfuzz/round_trip_stream_fuzzer.c
parent399a80d48e4352aeae99eb5cbd799bcee6978a3d (diff)
downloadlz4-675ef9a9fc9899667d0fe9b7b2a66e402e870a6d.tar.gz
[fuzz] Add HC fuzzers for round trip, compress, and streaming
Diffstat (limited to 'ossfuzz/round_trip_stream_fuzzer.c')
-rw-r--r--ossfuzz/round_trip_stream_fuzzer.c107
1 files changed, 96 insertions, 11 deletions
diff --git a/ossfuzz/round_trip_stream_fuzzer.c b/ossfuzz/round_trip_stream_fuzzer.c
index 4facfc94..abfcd2db 100644
--- a/ossfuzz/round_trip_stream_fuzzer.c
+++ b/ossfuzz/round_trip_stream_fuzzer.c
@@ -12,6 +12,8 @@
#include "fuzz_helpers.h"
#define LZ4_STATIC_LINKING_ONLY
#include "lz4.h"
+#define LZ4_HC_STATIC_LINKING_ONLY
+#include "lz4hc.h"
typedef struct {
char const* buf;
@@ -27,11 +29,13 @@ typedef struct {
typedef struct {
LZ4_stream_t* cstream;
+ LZ4_streamHC_t* cstreamHC;
LZ4_streamDecode_t* dstream;
const_cursor_t data;
cursor_t compressed;
cursor_t roundTrip;
uint32_t seed;
+ int level;
} state_t;
cursor_t cursor_create(size_t size)
@@ -44,6 +48,8 @@ cursor_t cursor_create(size_t size)
return cursor;
}
+typedef void (*round_trip_t)(state_t* state);
+
void cursor_free(cursor_t cursor)
{
free(cursor.buf);
@@ -65,6 +71,8 @@ state_t state_create(char const* data, size_t size, uint32_t seed)
state.cstream = LZ4_createStream();
FUZZ_ASSERT(state.cstream);
+ state.cstreamHC = LZ4_createStreamHC();
+ FUZZ_ASSERT(state.cstream);
state.dstream = LZ4_createStreamDecode();
FUZZ_ASSERT(state.dstream);
@@ -76,12 +84,15 @@ void state_free(state_t state)
cursor_free(state.compressed);
cursor_free(state.roundTrip);
LZ4_freeStream(state.cstream);
+ LZ4_freeStreamHC(state.cstreamHC);
LZ4_freeStreamDecode(state.dstream);
}
static void state_reset(state_t* state, uint32_t seed)
{
+ state->level = FUZZ_rand32(&seed, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
LZ4_resetStream_fast(state->cstream);
+ LZ4_resetStreamHC_fast(state->cstreamHC, state->level);
LZ4_setStreamDecode(state->dstream, NULL, 0);
state->data.pos = 0;
state->compressed.pos = 0;
@@ -109,14 +120,19 @@ static void state_checkRoundTrip(state_t const* state)
/**
* Picks a dictionary size and trims the dictionary off of the data.
+ * We copy the dictionary to the roundTrip so our validation passes.
*/
static size_t state_trimDict(state_t* state)
{
/* 64 KB is the max dict size, allow slightly beyond that to test trim. */
uint32_t maxDictSize = MIN(70 * 1024, state->data.size);
size_t const dictSize = FUZZ_rand32(&state->seed, 0, maxDictSize);
- FUZZ_ASSERT(state->compressed.pos == 0);
- state->compressed.pos += dictSize;
+ DEBUGLOG(2, "dictSize = %zu", dictSize);
+ FUZZ_ASSERT(state->data.pos == 0);
+ FUZZ_ASSERT(state->roundTrip.pos == 0);
+ memcpy(state->roundTrip.buf, state->data.buf, dictSize);
+ state->data.pos += dictSize;
+ state->roundTrip.pos += dictSize;
return dictSize;
}
@@ -159,43 +175,111 @@ static void state_extDictRoundTrip(state_t* state)
cursor_free(data2);
}
-static void state_randomRoundTrip(state_t* state)
+static void state_randomRoundTrip(state_t* state, round_trip_t rt0,
+ round_trip_t rt1)
{
if (FUZZ_rand32(&state->seed, 0, 1)) {
- state_prefixRoundTrip(state);
+ rt0(state);
} else {
- state_extDictRoundTrip(state);
+ rt1(state);
}
}
static void state_loadDictRoundTrip(state_t* state)
{
- char const* dict = state->compressed.buf;
+ char const* dict = state->data.buf;
size_t const dictSize = state_trimDict(state);
LZ4_loadDict(state->cstream, dict, dictSize);
LZ4_setStreamDecode(state->dstream, dict, dictSize);
- state_randomRoundTrip(state);
+ state_randomRoundTrip(state, state_prefixRoundTrip, state_extDictRoundTrip);
}
static void state_attachDictRoundTrip(state_t* state)
{
- char const* dict = state->compressed.buf;
+ char const* dict = state->data.buf;
size_t const dictSize = state_trimDict(state);
LZ4_stream_t* dictStream = LZ4_createStream();
LZ4_loadDict(dictStream, dict, dictSize);
LZ4_attach_dictionary(state->cstream, dictStream);
LZ4_setStreamDecode(state->dstream, dict, dictSize);
- state_randomRoundTrip(state);
+ state_randomRoundTrip(state, state_prefixRoundTrip, state_extDictRoundTrip);
LZ4_freeStream(dictStream);
}
-typedef void (*round_trip_t)(state_t* state);
+static void state_prefixHCRoundTrip(state_t* state)
+{
+ while (state->data.pos != state->data.size) {
+ char const* src = state->data.buf + state->data.pos;
+ char* dst = state->compressed.buf + state->compressed.pos;
+ int const srcRemaining = state->data.size - state->data.pos;
+ int const srcSize = FUZZ_rand32(&state->seed, 0, srcRemaining);
+ int const dstCapacity = state->compressed.size - state->compressed.pos;
+ int const cSize = LZ4_compress_HC_continue(state->cstreamHC, src, dst,
+ srcSize, dstCapacity);
+ FUZZ_ASSERT(cSize > 0);
+ state->data.pos += srcSize;
+ state->compressed.pos += cSize;
+ state_decompress(state, dst, cSize);
+ }
+}
+
+static void state_extDictHCRoundTrip(state_t* state)
+{
+ int i = 0;
+ cursor_t data2 = cursor_create(state->data.size);
+ DEBUGLOG(2, "extDictHC");
+ memcpy(data2.buf, state->data.buf, state->data.size);
+ while (state->data.pos != state->data.size) {
+ char const* data = (i++ & 1) ? state->data.buf : data2.buf;
+ char const* src = data + state->data.pos;
+ char* dst = state->compressed.buf + state->compressed.pos;
+ int const srcRemaining = state->data.size - state->data.pos;
+ int const srcSize = FUZZ_rand32(&state->seed, 0, srcRemaining);
+ int const dstCapacity = state->compressed.size - state->compressed.pos;
+ int const cSize = LZ4_compress_HC_continue(state->cstreamHC, src, dst,
+ srcSize, dstCapacity);
+ FUZZ_ASSERT(cSize > 0);
+ DEBUGLOG(2, "srcSize = %d", srcSize);
+ state->data.pos += srcSize;
+ state->compressed.pos += cSize;
+ state_decompress(state, dst, cSize);
+ }
+ cursor_free(data2);
+}
+
+static void state_loadDictHCRoundTrip(state_t* state)
+{
+ char const* dict = state->data.buf;
+ size_t const dictSize = state_trimDict(state);
+ LZ4_loadDictHC(state->cstreamHC, dict, dictSize);
+ LZ4_setStreamDecode(state->dstream, dict, dictSize);
+ state_randomRoundTrip(state, state_prefixHCRoundTrip,
+ state_extDictHCRoundTrip);
+}
+
+static void state_attachDictHCRoundTrip(state_t* state)
+{
+ char const* dict = state->data.buf;
+ size_t const dictSize = state_trimDict(state);
+ LZ4_streamHC_t* dictStream = LZ4_createStreamHC();
+ LZ4_setCompressionLevel(dictStream, state->level);
+ LZ4_loadDictHC(dictStream, dict, dictSize);
+ LZ4_attach_HC_dictionary(state->cstreamHC, dictStream);
+ LZ4_setStreamDecode(state->dstream, dict, dictSize);
+ state_randomRoundTrip(state, state_prefixHCRoundTrip,
+ state_extDictHCRoundTrip);
+ LZ4_freeStreamHC(dictStream);
+}
round_trip_t roundTrips[] = {
&state_prefixRoundTrip,
&state_extDictRoundTrip,
&state_loadDictRoundTrip,
&state_attachDictRoundTrip,
+ &state_prefixHCRoundTrip,
+ &state_extDictHCRoundTrip,
+ &state_loadDictHCRoundTrip,
+ &state_attachDictHCRoundTrip,
};
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
@@ -206,9 +290,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
int i;
for (i = 0; i < n; ++i) {
+ DEBUGLOG(2, "Round trip %d", i);
+ state_reset(&state, seed);
roundTrips[i](&state);
state_checkRoundTrip(&state);
- state_reset(&state, seed);
}
state_free(state);