1 /*
2 * Copyright (c) 2016-present, Facebook, Inc.
3 * All rights reserved.
4 *
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).
8 */
9
10 /**
11 * This fuzz target performs a zstd round-trip test (compress & decompress) with
12 * a dictionary, compares the result with the original, and calls abort() on
13 * corruption.
14 */
15
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include "fuzz_helpers.h"
21 #include "zstd_helpers.h"
22 #include "fuzz_data_producer.h"
23
24 static ZSTD_CCtx *cctx = NULL;
25 static ZSTD_DCtx *dctx = NULL;
26
roundTripTest(void * result,size_t resultCapacity,void * compressed,size_t compressedCapacity,const void * src,size_t srcSize,FUZZ_dataProducer_t * producer)27 static size_t roundTripTest(void *result, size_t resultCapacity,
28 void *compressed, size_t compressedCapacity,
29 const void *src, size_t srcSize,
30 FUZZ_dataProducer_t *producer)
31 {
32 ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto;
33 FUZZ_dict_t dict = FUZZ_train(src, srcSize, producer);
34 size_t cSize;
35 if (FUZZ_dataProducer_uint32Range(producer, 0, 15) == 0) {
36 int const cLevel = FUZZ_dataProducer_int32Range(producer, kMinClevel, kMaxClevel);
37
38 cSize = ZSTD_compress_usingDict(cctx,
39 compressed, compressedCapacity,
40 src, srcSize,
41 dict.buff, dict.size,
42 cLevel);
43 } else {
44 dictContentType = FUZZ_dataProducer_uint32Range(producer, 0, 2);
45 FUZZ_setRandomParameters(cctx, srcSize, producer);
46 /* Disable checksum so we can use sizes smaller than compress bound. */
47 FUZZ_ZASSERT(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0));
48 FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
49 cctx, dict.buff, dict.size,
50 (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
51 dictContentType));
52 cSize = ZSTD_compress2(cctx, compressed, compressedCapacity, src, srcSize);
53 }
54 FUZZ_ZASSERT(cSize);
55 FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
56 dctx, dict.buff, dict.size,
57 (ZSTD_dictLoadMethod_e)FUZZ_dataProducer_uint32Range(producer, 0, 1),
58 dictContentType));
59 {
60 size_t const ret = ZSTD_decompressDCtx(
61 dctx, result, resultCapacity, compressed, cSize);
62 free(dict.buff);
63 return ret;
64 }
65 }
66
LLVMFuzzerTestOneInput(const uint8_t * src,size_t size)67 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
68 {
69 /* Give a random portion of src data to the producer, to use for
70 parameter generation. The rest will be used for (de)compression */
71 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
72 size = FUZZ_dataProducer_reserveDataPrefix(producer);
73
74 size_t const rBufSize = size;
75 void* rBuf = malloc(rBufSize);
76 size_t cBufSize = ZSTD_compressBound(size);
77 void *cBuf;
78 /* Half of the time fuzz with a 1 byte smaller output size.
79 * This will still succeed because we force the checksum to be disabled,
80 * giving us 4 bytes of overhead.
81 */
82 cBufSize -= FUZZ_dataProducer_uint32Range(producer, 0, 1);
83 cBuf = malloc(cBufSize);
84
85 if (!cctx) {
86 cctx = ZSTD_createCCtx();
87 FUZZ_ASSERT(cctx);
88 }
89 if (!dctx) {
90 dctx = ZSTD_createDCtx();
91 FUZZ_ASSERT(dctx);
92 }
93
94 {
95 size_t const result =
96 roundTripTest(rBuf, rBufSize, cBuf, cBufSize, src, size, producer);
97 FUZZ_ZASSERT(result);
98 FUZZ_ASSERT_MSG(result == size, "Incorrect regenerated size");
99 FUZZ_ASSERT_MSG(!memcmp(src, rBuf, size), "Corruption!");
100 }
101 free(rBuf);
102 free(cBuf);
103 FUZZ_dataProducer_free(producer);
104 #ifndef STATEFUL_FUZZING
105 ZSTD_freeCCtx(cctx); cctx = NULL;
106 ZSTD_freeDCtx(dctx); dctx = NULL;
107 #endif
108 return 0;
109 }
110