/src/zstd/tests/fuzz/huf_round_trip.c
Line | Count | Source |
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 performs a zstd round-trip test (compress & decompress), |
13 | | * compares the result with the original, and calls abort() on corruption. |
14 | | */ |
15 | | |
16 | | #include <stddef.h> |
17 | | #include <stdlib.h> |
18 | | #include <stdio.h> |
19 | | #include <string.h> |
20 | | #include "common/cpu.h" |
21 | | #include "compress/hist.h" |
22 | | #include "common/huf.h" |
23 | | #include "fuzz_helpers.h" |
24 | | #include "fuzz_data_producer.h" |
25 | | #include "common/bits.h" |
26 | | |
27 | | static size_t adjustTableLog(size_t tableLog, size_t maxSymbol) |
28 | 4.87k | { |
29 | 4.87k | size_t const alphabetSize = maxSymbol + 1; |
30 | 4.87k | size_t minTableLog = ZSTD_highbit32(alphabetSize) + 1; |
31 | 4.87k | if ((alphabetSize & (alphabetSize - 1)) != 0) { |
32 | 1.80k | ++minTableLog; |
33 | 1.80k | } |
34 | 4.87k | assert(minTableLog <= 9); |
35 | 4.87k | if (tableLog < minTableLog) |
36 | 2.05k | return minTableLog; |
37 | 2.82k | else |
38 | 2.82k | return tableLog; |
39 | 4.87k | } |
40 | | |
41 | | int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) |
42 | 4.90k | { |
43 | 4.90k | FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); |
44 | | /* Select random parameters: #streams, X1 or X2 decoding, bmi2 */ |
45 | 4.90k | int const streams = FUZZ_dataProducer_int32Range(producer, 0, 1); |
46 | 4.90k | int const symbols = FUZZ_dataProducer_int32Range(producer, 0, 1); |
47 | 4.90k | int const flags = 0 |
48 | 4.90k | | (ZSTD_cpuid_bmi2(ZSTD_cpuid()) && FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_bmi2 : 0) |
49 | 4.90k | | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_optimalDepth : 0) |
50 | 4.90k | | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_preferRepeat : 0) |
51 | 4.90k | | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_suspectUncompressible : 0) |
52 | 4.90k | | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_disableAsm : 0) |
53 | 4.90k | | (FUZZ_dataProducer_int32Range(producer, 0, 1) ? HUF_flags_disableFast : 0); |
54 | | /* Select a random cBufSize - it may be too small */ |
55 | 4.90k | size_t const cBufSize = FUZZ_dataProducer_uint32Range(producer, 0, 4 * size); |
56 | | /* Select a random tableLog - we'll adjust it up later */ |
57 | 4.90k | size_t tableLog = FUZZ_dataProducer_uint32Range(producer, 1, 12); |
58 | 4.90k | size_t const kMaxSize = 256 * 1024; |
59 | 4.90k | size = FUZZ_dataProducer_remainingBytes(producer); |
60 | 4.90k | if (size > kMaxSize) |
61 | 37 | size = kMaxSize; |
62 | | |
63 | 4.90k | if (size <= 1) { |
64 | 13 | FUZZ_dataProducer_free(producer); |
65 | 13 | return 0; |
66 | 13 | } |
67 | | |
68 | 4.89k | uint32_t maxSymbol = 255; |
69 | | |
70 | 4.89k | U32 count[256]; |
71 | 4.89k | size_t const mostFrequent = HIST_count(count, &maxSymbol, src, size); |
72 | 4.89k | FUZZ_ZASSERT(mostFrequent); |
73 | 4.89k | if (mostFrequent == size) { |
74 | | /* RLE */ |
75 | 15 | FUZZ_dataProducer_free(producer); |
76 | 15 | return 0; |
77 | | |
78 | 15 | } |
79 | 4.87k | FUZZ_ASSERT(maxSymbol <= 255); |
80 | 4.87k | tableLog = adjustTableLog(tableLog, maxSymbol); |
81 | | |
82 | 4.87k | size_t const wkspSize = HUF_WORKSPACE_SIZE; |
83 | 4.87k | void* wksp = FUZZ_malloc(wkspSize); |
84 | 4.87k | void* rBuf = FUZZ_malloc(size); |
85 | 4.87k | void* cBuf = FUZZ_malloc(cBufSize); |
86 | 4.87k | HUF_CElt* ct = (HUF_CElt*)FUZZ_malloc(HUF_CTABLE_SIZE(maxSymbol)); |
87 | 4.87k | HUF_DTable* dt = (HUF_DTable*)FUZZ_malloc(HUF_DTABLE_SIZE(tableLog) * sizeof(HUF_DTable)); |
88 | 4.87k | dt[0] = tableLog * 0x01000001; |
89 | | |
90 | 4.87k | tableLog = HUF_optimalTableLog(tableLog, size, maxSymbol, wksp, wkspSize, ct, count, flags); |
91 | 4.87k | FUZZ_ASSERT(tableLog <= 12); |
92 | 4.87k | tableLog = HUF_buildCTable_wksp(ct, count, maxSymbol, tableLog, wksp, wkspSize); |
93 | 4.87k | FUZZ_ZASSERT(tableLog); |
94 | 4.87k | size_t const tableSize = HUF_writeCTable_wksp(cBuf, cBufSize, ct, maxSymbol, tableLog, wksp, wkspSize); |
95 | 4.87k | if (ERR_isError(tableSize)) { |
96 | | /* Errors on uncompressible data or cBufSize too small */ |
97 | 136 | goto _out; |
98 | 136 | } |
99 | 4.74k | FUZZ_ZASSERT(tableSize); |
100 | 4.74k | if (symbols == 0) { |
101 | 1.97k | FUZZ_ZASSERT(HUF_readDTableX1_wksp(dt, cBuf, tableSize, wksp, wkspSize, flags)); |
102 | 2.76k | } else { |
103 | 2.76k | size_t const ret = HUF_readDTableX2_wksp(dt, cBuf, tableSize, wksp, wkspSize, flags); |
104 | 2.76k | if (ERR_getErrorCode(ret) == ZSTD_error_tableLog_tooLarge) { |
105 | 7 | FUZZ_ZASSERT(HUF_readDTableX1_wksp(dt, cBuf, tableSize, wksp, wkspSize, flags)); |
106 | 2.76k | } else { |
107 | 2.76k | FUZZ_ZASSERT(ret); |
108 | 2.76k | } |
109 | 2.76k | } |
110 | | |
111 | 4.74k | size_t cSize; |
112 | 4.74k | size_t rSize; |
113 | 4.74k | if (streams == 0) { |
114 | 1.45k | cSize = HUF_compress1X_usingCTable(cBuf, cBufSize, src, size, ct, flags); |
115 | 1.45k | FUZZ_ZASSERT(cSize); |
116 | 1.45k | if (cSize != 0) |
117 | 1.33k | rSize = HUF_decompress1X_usingDTable(rBuf, size, cBuf, cSize, dt, flags); |
118 | 3.28k | } else { |
119 | 3.28k | cSize = HUF_compress4X_usingCTable(cBuf, cBufSize, src, size, ct, flags); |
120 | 3.28k | FUZZ_ZASSERT(cSize); |
121 | 3.28k | if (cSize != 0) |
122 | 3.05k | rSize = HUF_decompress4X_usingDTable(rBuf, size, cBuf, cSize, dt, flags); |
123 | 3.28k | } |
124 | 4.74k | if (cSize != 0) { |
125 | 4.39k | FUZZ_ZASSERT(rSize); |
126 | 4.39k | FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size"); |
127 | 4.39k | FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!"); |
128 | 4.39k | } |
129 | 4.87k | _out: |
130 | 4.87k | free(rBuf); |
131 | 4.87k | free(cBuf); |
132 | 4.87k | free(ct); |
133 | 4.87k | free(dt); |
134 | 4.87k | free(wksp); |
135 | 4.87k | FUZZ_dataProducer_free(producer); |
136 | 4.87k | return 0; |
137 | 4.74k | } |