1 /*
2 * Copyright (c) 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 * You may select, at your option, one of the above-listed licenses.
9 */
10
11 /**
12 * This fuzz target makes sure that whenever a compression dictionary can be
13 * loaded, the data can be round tripped.
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 /**
25 * Compresses the data and returns the compressed size or an error.
26 */
compress(void * compressed,size_t compressedCapacity,void const * source,size_t sourceSize,void const * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,int const refPrefix)27 static size_t compress(void* compressed, size_t compressedCapacity,
28 void const* source, size_t sourceSize,
29 void const* dict, size_t dictSize,
30 ZSTD_dictLoadMethod_e dictLoadMethod,
31 ZSTD_dictContentType_e dictContentType,
32 int const refPrefix)
33 {
34 ZSTD_CCtx* cctx = ZSTD_createCCtx();
35 if (refPrefix)
36 FUZZ_ZASSERT(ZSTD_CCtx_refPrefix_advanced(
37 cctx, dict, dictSize, dictContentType));
38 else
39 FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced(
40 cctx, dict, dictSize, dictLoadMethod, dictContentType));
41 size_t const compressedSize = ZSTD_compress2(
42 cctx, compressed, compressedCapacity, source, sourceSize);
43 ZSTD_freeCCtx(cctx);
44 return compressedSize;
45 }
46
decompress(void * result,size_t resultCapacity,void const * compressed,size_t compressedSize,void const * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,int const refPrefix)47 static size_t decompress(void* result, size_t resultCapacity,
48 void const* compressed, size_t compressedSize,
49 void const* dict, size_t dictSize,
50 ZSTD_dictLoadMethod_e dictLoadMethod,
51 ZSTD_dictContentType_e dictContentType,
52 int const refPrefix)
53 {
54 ZSTD_DCtx* dctx = ZSTD_createDCtx();
55 if (refPrefix)
56 FUZZ_ZASSERT(ZSTD_DCtx_refPrefix_advanced(
57 dctx, dict, dictSize, dictContentType));
58 else
59 FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced(
60 dctx, dict, dictSize, dictLoadMethod, dictContentType));
61 size_t const resultSize = ZSTD_decompressDCtx(
62 dctx, result, resultCapacity, compressed, compressedSize);
63 FUZZ_ZASSERT(resultSize);
64 ZSTD_freeDCtx(dctx);
65 return resultSize;
66 }
67
LLVMFuzzerTestOneInput(const uint8_t * src,size_t size)68 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
69 {
70 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
71 int const refPrefix = FUZZ_dataProducer_uint32Range(producer, 0, 1) != 0;
72 ZSTD_dictLoadMethod_e const dlm =
73 size = FUZZ_dataProducer_uint32Range(producer, 0, 1);
74 ZSTD_dictContentType_e const dct =
75 FUZZ_dataProducer_uint32Range(producer, 0, 2);
76 size = FUZZ_dataProducer_remainingBytes(producer);
77
78 DEBUGLOG(2, "Dict load method %d", dlm);
79 DEBUGLOG(2, "Dict content type %d", dct);
80 DEBUGLOG(2, "Dict size %u", (unsigned)size);
81
82 void* const rBuf = FUZZ_malloc(size);
83 size_t const cBufSize = ZSTD_compressBound(size);
84 void* const cBuf = FUZZ_malloc(cBufSize);
85
86 size_t const cSize =
87 compress(cBuf, cBufSize, src, size, src, size, dlm, dct, refPrefix);
88 /* compression failing is okay */
89 if (ZSTD_isError(cSize)) {
90 FUZZ_ASSERT_MSG(dct != ZSTD_dct_rawContent, "Raw must always succeed!");
91 goto out;
92 }
93 size_t const rSize =
94 decompress(rBuf, size, cBuf, cSize, src, size, dlm, dct, refPrefix);
95 FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size");
96 FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!");
97
98 out:
99 free(cBuf);
100 free(rBuf);
101 FUZZ_dataProducer_free(producer);
102 return 0;
103 }
104