2 * Copyright (c) 2016-present, Facebook, Inc.
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
11 * This fuzz target performs a zstd round-trip test (compress & decompress),
12 * compares the result with the original, and calls abort() on corruption.
15 #define ZSTD_STATIC_LINKING_ONLY
21 #include "fuzz_helpers.h"
22 #include "zstd_helpers.h"
23 #include "fuzz_data_producer.h"
25 ZSTD_CCtx *cctx = NULL;
26 static ZSTD_DCtx *dctx = NULL;
27 static uint8_t* cBuf = NULL;
28 static uint8_t* rBuf = NULL;
29 static size_t bufSize = 0;
31 static ZSTD_outBuffer makeOutBuffer(uint8_t *dst, size_t capacity,
32 FUZZ_dataProducer_t *producer)
34 ZSTD_outBuffer buffer = { dst, 0, 0 };
36 FUZZ_ASSERT(capacity > 0);
37 buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, capacity));
38 FUZZ_ASSERT(buffer.size <= capacity);
43 static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
44 FUZZ_dataProducer_t *producer)
46 ZSTD_inBuffer buffer = { *src, 0, 0 };
48 FUZZ_ASSERT(*size > 0);
49 buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, *size));
50 FUZZ_ASSERT(buffer.size <= *size);
57 static size_t compress(uint8_t *dst, size_t capacity,
58 const uint8_t *src, size_t srcSize,
59 FUZZ_dataProducer_t *producer)
62 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
63 FUZZ_setRandomParameters(cctx, srcSize, producer);
66 ZSTD_inBuffer in = makeInBuffer(&src, &srcSize, producer);
67 /* Mode controls the action. If mode == -1 we pick a new mode */
69 while (in.pos < in.size || mode != -1) {
70 ZSTD_outBuffer out = makeOutBuffer(dst, capacity, producer);
71 /* Previous action finished, pick a new mode. */
72 if (mode == -1) mode = FUZZ_dataProducer_uint32Range(producer, 0, 9);
74 case 0: /* fall-through */
75 case 1: /* fall-through */
78 ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush);
86 ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
88 /* Reset the compressor when the frame is finished */
90 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
91 if (FUZZ_dataProducer_uint32Range(producer, 0, 7) == 0) {
92 size_t const remaining = in.size - in.pos;
93 FUZZ_setRandomParameters(cctx, remaining, producer);
101 ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);
112 ZSTD_inBuffer in = {NULL, 0, 0};
113 ZSTD_outBuffer out = makeOutBuffer(dst, capacity, producer);
114 size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
126 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
128 size_t neededBufSize;
130 /* Give a random portion of src data to the producer, to use for
131 parameter generation. The rest will be used for (de)compression */
132 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
133 size = FUZZ_dataProducer_reserveDataPrefix(producer);
135 neededBufSize = ZSTD_compressBound(size) * 15;
137 /* Allocate all buffers and contexts if not already allocated */
138 if (neededBufSize > bufSize) {
141 cBuf = (uint8_t*)malloc(neededBufSize);
142 rBuf = (uint8_t*)malloc(neededBufSize);
143 bufSize = neededBufSize;
144 FUZZ_ASSERT(cBuf && rBuf);
147 cctx = ZSTD_createCCtx();
151 dctx = ZSTD_createDCtx();
156 size_t const cSize = compress(cBuf, neededBufSize, src, size, producer);
158 ZSTD_decompressDCtx(dctx, rBuf, neededBufSize, cBuf, cSize);
160 FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size");
161 FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
164 FUZZ_dataProducer_free(producer);
165 #ifndef STATEFUL_FUZZING
166 ZSTD_freeCCtx(cctx); cctx = NULL;
167 ZSTD_freeDCtx(dctx); dctx = NULL;