/src/flac/oss-fuzz/encoder.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2019 Guido Vranken |
2 | | * |
3 | | * Permission is hereby granted, free of charge, to any person obtaining |
4 | | * a copy of this software and associated documentation files (the |
5 | | * "Software"), to deal in the Software without restriction, including |
6 | | * without limitation the rights to use, copy, modify, merge, publish, |
7 | | * distribute, sublicense, and/or sell copies of the Software, and to |
8 | | * permit persons to whom the Software is furnished to do so, subject |
9 | | * to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be |
12 | | * included in all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
15 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
16 | | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
17 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
18 | | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
19 | | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
20 | | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | | * SOFTWARE. |
22 | | */ |
23 | | |
24 | | #include <cstddef> |
25 | | #include <cstdint> |
26 | | #include <limits> |
27 | | |
28 | | #include <fuzzing/datasource/datasource.hpp> |
29 | | #include <fuzzing/memory.hpp> |
30 | | |
31 | | #include "FLAC++/encoder.h" |
32 | | #include "common.h" |
33 | | |
34 | | namespace FLAC { |
35 | | namespace Encoder { |
36 | | class FuzzerStream : public Stream { |
37 | | private: |
38 | | // fuzzing::datasource::Datasource& ds; |
39 | | public: |
40 | | FuzzerStream(fuzzing::datasource::Datasource&) : |
41 | 20.4k | Stream() { } |
42 | | |
43 | 2.63M | ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override { |
44 | 2.63M | fuzzing::memory::memory_test(buffer, bytes); |
45 | | #if 0 |
46 | | try { |
47 | | if ( ds.Get<bool>() == true ) { |
48 | | return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; |
49 | | } |
50 | | } catch ( ... ) { } |
51 | | #endif |
52 | 2.63M | return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; |
53 | 2.63M | } |
54 | | }; |
55 | | } |
56 | | } |
57 | | |
58 | 12.2k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
59 | 12.2k | fuzzing::datasource::Datasource ds(data, size); |
60 | 12.2k | FLAC::Encoder::FuzzerStream encoder(ds); |
61 | | |
62 | 12.2k | try { |
63 | 12.2k | const int channels = ds.Get<uint8_t>(); |
64 | 12.2k | const int bps = ds.Get<uint8_t>(); |
65 | 12.2k | encoder.set_channels(channels); |
66 | 12.2k | encoder.set_bits_per_sample(bps); |
67 | | |
68 | 12.2k | { |
69 | 12.2k | const bool res = encoder.set_streamable_subset(ds.Get<bool>()); |
70 | 12.2k | fuzzing::memory::memory_test(res); |
71 | 12.2k | } |
72 | 12.2k | { |
73 | 12.2k | const bool res = encoder.set_ogg_serial_number(ds.Get<long>()); |
74 | 12.2k | fuzzing::memory::memory_test(res); |
75 | 12.2k | } |
76 | 12.2k | { |
77 | 12.2k | const bool res = encoder.set_verify(ds.Get<bool>()); |
78 | 12.2k | fuzzing::memory::memory_test(res); |
79 | 12.2k | } |
80 | 12.2k | { |
81 | 12.2k | const bool res = encoder.set_compression_level(ds.Get<uint8_t>()); |
82 | 12.2k | fuzzing::memory::memory_test(res); |
83 | 12.2k | } |
84 | 12.2k | { |
85 | 12.2k | const bool res = encoder.set_do_exhaustive_model_search(ds.Get<bool>()); |
86 | 12.2k | fuzzing::memory::memory_test(res); |
87 | 12.2k | } |
88 | 12.2k | { |
89 | 12.2k | const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>()); |
90 | 12.2k | fuzzing::memory::memory_test(res); |
91 | 12.2k | } |
92 | 12.2k | { |
93 | 12.2k | const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>()); |
94 | 12.2k | fuzzing::memory::memory_test(res); |
95 | 12.2k | } |
96 | 12.2k | { |
97 | 12.2k | const auto s = ds.Get<std::string>(); |
98 | 12.2k | const bool res = encoder.set_apodization(s.data()); |
99 | 12.2k | fuzzing::memory::memory_test(res); |
100 | 12.2k | } |
101 | 12.2k | { |
102 | 12.2k | const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>()); |
103 | 12.2k | fuzzing::memory::memory_test(res); |
104 | 12.2k | } |
105 | 12.2k | { |
106 | 12.2k | const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>()); |
107 | 12.2k | fuzzing::memory::memory_test(res); |
108 | 12.2k | } |
109 | 12.2k | { |
110 | 12.2k | const bool res = encoder.set_do_qlp_coeff_prec_search(ds.Get<bool>()); |
111 | 12.2k | fuzzing::memory::memory_test(res); |
112 | 12.2k | } |
113 | 12.2k | { |
114 | 12.2k | const bool res = encoder.set_do_escape_coding(ds.Get<bool>()); |
115 | 12.2k | fuzzing::memory::memory_test(res); |
116 | 12.2k | } |
117 | 12.2k | { |
118 | 12.2k | const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>()); |
119 | 12.2k | fuzzing::memory::memory_test(res); |
120 | 12.2k | } |
121 | 12.2k | { |
122 | 12.2k | const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>()); |
123 | 12.2k | fuzzing::memory::memory_test(res); |
124 | 12.2k | } |
125 | 12.2k | { |
126 | 12.2k | const bool res = encoder.set_rice_parameter_search_dist(ds.Get<uint32_t>()); |
127 | 12.2k | fuzzing::memory::memory_test(res); |
128 | 12.2k | } |
129 | 12.2k | { |
130 | 12.2k | const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>()); |
131 | 12.2k | fuzzing::memory::memory_test(res); |
132 | 12.2k | } |
133 | 12.2k | { |
134 | 12.2k | const bool res = encoder.set_blocksize(ds.Get<uint16_t>()); |
135 | 12.2k | fuzzing::memory::memory_test(res); |
136 | 12.2k | } |
137 | 12.2k | { |
138 | 12.2k | const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>()); |
139 | 12.2k | fuzzing::memory::memory_test(res); |
140 | 12.2k | } |
141 | 12.2k | { |
142 | 12.2k | const bool res = encoder.set_sample_rate(ds.Get<uint32_t>()); |
143 | 12.2k | fuzzing::memory::memory_test(res); |
144 | 12.2k | } |
145 | 12.2k | { |
146 | 12.2k | const bool res = encoder.set_num_threads(ds.Get<uint32_t>()); |
147 | 12.2k | fuzzing::memory::memory_test(res); |
148 | 12.2k | } |
149 | | |
150 | 12.2k | if ( size > 2 * 65535 * 4 ) { |
151 | | /* With large inputs and expensive options enabled, the fuzzer can get *really* slow. |
152 | | * Some combinations can make the fuzzer timeout (>60 seconds). However, while combining |
153 | | * options makes the fuzzer slower, most options do not expose new code when combined. |
154 | | * Therefore, combining slow options is disabled for large inputs. Any input containing |
155 | | * more than 65536 * 2 samples of 32 bits each (max blocksize, stereo) is considered large |
156 | | */ |
157 | 183 | encoder.set_do_qlp_coeff_prec_search(false); |
158 | 183 | encoder.set_do_exhaustive_model_search(false); |
159 | 183 | } |
160 | 12.2k | if ( size > 2 * 4096 * 4 + 250 ) { |
161 | | /* With subdivide_tukey in the mix testing apodizations can get really expensive. Therefore |
162 | | * this is disabled for inputs of more than one whole stereo block of 32-bit inputs plus a |
163 | | * bit of overhead */ |
164 | 1.39k | encoder.set_apodization(""); |
165 | 1.39k | } |
166 | | |
167 | 12.2k | { |
168 | 12.2k | ::FLAC__StreamEncoderInitStatus ret; |
169 | 12.2k | if ( ds.Get<bool>() ) { |
170 | 6.79k | ret = encoder.init(); |
171 | 6.79k | } else { |
172 | 5.45k | ret = encoder.init_ogg(); |
173 | 5.45k | } |
174 | | |
175 | 12.2k | if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) { |
176 | 243 | goto end; |
177 | 243 | } |
178 | 12.2k | } |
179 | | |
180 | | /* These sets must fail, because encoder is already initialized */ |
181 | 12.0k | { |
182 | 12.0k | bool res = false; |
183 | 12.0k | res = res || encoder.set_streamable_subset(true); |
184 | 12.0k | res = res || encoder.set_ogg_serial_number(0); |
185 | 12.0k | res = res || encoder.set_verify(true); |
186 | 12.0k | res = res || encoder.set_compression_level(0); |
187 | 12.0k | res = res || encoder.set_do_exhaustive_model_search(true); |
188 | 12.0k | res = res || encoder.set_do_mid_side_stereo(true); |
189 | 12.0k | res = res || encoder.set_loose_mid_side_stereo(true); |
190 | 12.0k | res = res || encoder.set_apodization("test"); |
191 | 12.0k | res = res || encoder.set_max_lpc_order(0); |
192 | 12.0k | res = res || encoder.set_qlp_coeff_precision(0); |
193 | 12.0k | res = res || encoder.set_do_qlp_coeff_prec_search(true); |
194 | 12.0k | res = res || encoder.set_do_escape_coding(true); |
195 | 12.0k | res = res || encoder.set_min_residual_partition_order(0); |
196 | 12.0k | res = res || encoder.set_max_residual_partition_order(0); |
197 | 12.0k | res = res || encoder.set_rice_parameter_search_dist(0); |
198 | 12.0k | res = res || encoder.set_total_samples_estimate(0); |
199 | 12.0k | res = res || encoder.set_channels(channels); |
200 | 12.0k | res = res || encoder.set_bits_per_sample(16); |
201 | 12.0k | res = res || encoder.set_limit_min_bitrate(true); |
202 | 12.0k | res = res || encoder.set_blocksize(3021); |
203 | 12.0k | res = res || encoder.set_sample_rate(44100); |
204 | 12.0k | res = res || (encoder.set_num_threads(4) == FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK); |
205 | 12.0k | fuzzing::memory::memory_test(res); |
206 | 12.0k | if(res) |
207 | 0 | abort(); |
208 | 12.0k | } |
209 | | |
210 | | |
211 | 12.0k | { |
212 | | /* XORing values as otherwise compiler will optimize, apparently */ |
213 | 12.0k | bool res = false; |
214 | 12.0k | res = res != encoder.get_streamable_subset(); |
215 | 12.0k | res = res != encoder.get_verify(); |
216 | 12.0k | res = res != encoder.get_do_exhaustive_model_search(); |
217 | 12.0k | res = res != encoder.get_do_mid_side_stereo(); |
218 | 12.0k | res = res != encoder.get_loose_mid_side_stereo(); |
219 | 12.0k | res = res != encoder.get_max_lpc_order(); |
220 | 12.0k | res = res != encoder.get_qlp_coeff_precision(); |
221 | 12.0k | res = res != encoder.get_do_qlp_coeff_prec_search(); |
222 | 12.0k | res = res != encoder.get_do_escape_coding(); |
223 | 12.0k | res = res != encoder.get_min_residual_partition_order(); |
224 | 12.0k | res = res != encoder.get_max_residual_partition_order(); |
225 | 12.0k | res = res != encoder.get_rice_parameter_search_dist(); |
226 | 12.0k | res = res != encoder.get_total_samples_estimate(); |
227 | 12.0k | res = res != encoder.get_channels(); |
228 | 12.0k | res = res != encoder.get_bits_per_sample(); |
229 | 12.0k | res = res != encoder.get_limit_min_bitrate(); |
230 | 12.0k | res = res != encoder.get_blocksize(); |
231 | 12.0k | res = res != encoder.get_sample_rate(); |
232 | 12.0k | res = res != encoder.get_num_threads(); |
233 | 12.0k | fuzzing::memory::memory_test(res); |
234 | 12.0k | } |
235 | | |
236 | | |
237 | 202k | while ( ds.Get<bool>() ) { |
238 | 190k | { |
239 | 190k | auto dat = ds.GetVector<FLAC__int32>(); |
240 | | |
241 | 190k | if( ds.Get<bool>() ) |
242 | | /* Mask */ |
243 | 22.2M | for (size_t i = 0; i < dat.size(); i++) |
244 | | /* If we get here, bps is 4 or larger, or init will have failed */ |
245 | 22.0M | dat[i] = (int32_t)(((uint32_t)(dat[i]) << (32-bps)) >> (32-bps)); |
246 | | |
247 | 190k | const uint32_t samples = dat.size() / channels; |
248 | 190k | if ( samples > 0 ) { |
249 | 161k | const int32_t* ptr = dat.data(); |
250 | 161k | const bool res = encoder.process_interleaved(ptr, samples); |
251 | 161k | fuzzing::memory::memory_test(res); |
252 | 161k | } |
253 | 190k | } |
254 | 190k | } |
255 | 12.0k | } catch ( ... ) { } |
256 | | |
257 | 12.2k | end: |
258 | 12.2k | { |
259 | 12.2k | const bool res = encoder.finish(); |
260 | 12.2k | fuzzing::memory::memory_test(res); |
261 | 12.2k | } |
262 | 12.2k | return 0; |
263 | 12.2k | } |