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