/src/flac/oss-fuzz/reencoder.cc
Line | Count | Source |
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 "FLAC++/decoder.h" |
33 | | #include "FLAC++/metadata.h" |
34 | | #include "common.h" |
35 | | |
36 | 40.0k | #define MAX_NUM_METADATA_BLOCKS 2048 |
37 | | |
38 | | namespace FLAC { |
39 | | namespace Encoder { |
40 | | class FuzzerStream : public Stream { |
41 | | private: |
42 | | // fuzzing::datasource::Datasource& ds; |
43 | | public: |
44 | | FuzzerStream(fuzzing::datasource::Datasource&) : |
45 | 19.7k | Stream() { } |
46 | | |
47 | 2.14M | ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override { |
48 | 2.14M | fuzzing::memory::memory_test(buffer, bytes); |
49 | 2.14M | return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; |
50 | 2.14M | } |
51 | | }; |
52 | | } |
53 | | namespace Decoder { |
54 | | class FuzzerDecoder : public Stream { |
55 | | private: |
56 | | fuzzing::datasource::Datasource& ds; |
57 | | FLAC::Encoder::FuzzerStream& encoder; |
58 | | public: |
59 | | FuzzerDecoder(fuzzing::datasource::Datasource& dsrc, FLAC::Encoder::FuzzerStream& encoder_arg) : |
60 | 7.79k | Stream(), ds(dsrc), encoder(encoder_arg) { } |
61 | | |
62 | | ::FLAC__StreamMetadata * metadata_blocks[MAX_NUM_METADATA_BLOCKS] = {0}; |
63 | | int num_metadata_blocks = 0; |
64 | | |
65 | 40.0k | void metadata_callback(const ::FLAC__StreamMetadata *metadata) override { |
66 | 40.0k | if(num_metadata_blocks < MAX_NUM_METADATA_BLOCKS) |
67 | 39.8k | if((metadata_blocks[num_metadata_blocks] = FLAC__metadata_object_clone(metadata)) != NULL) |
68 | 39.8k | num_metadata_blocks++; |
69 | 40.0k | } |
70 | | |
71 | 80.8k | ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override { |
72 | 80.8k | try { |
73 | 80.8k | const size_t maxCopySize = *bytes; |
74 | | |
75 | 80.8k | if ( maxCopySize > 0 ) { |
76 | | /* memset just to test if this overwrites anything, and triggers ASAN */ |
77 | 80.8k | memset(buffer, 0, maxCopySize); |
78 | 80.8k | } |
79 | | |
80 | 80.8k | const auto data = ds.GetData(0); |
81 | 80.8k | const auto dataSize = data.size(); |
82 | 80.8k | const auto copySize = std::min(maxCopySize, dataSize); |
83 | | |
84 | 80.8k | if ( copySize > 0 ) { |
85 | 14.3k | memcpy(buffer, data.data(), copySize); |
86 | 14.3k | } |
87 | | |
88 | 80.8k | *bytes = copySize; |
89 | | |
90 | 80.8k | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
91 | 80.8k | } catch ( ... ) { |
92 | 6.94k | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
93 | 6.94k | } |
94 | 80.8k | } |
95 | | |
96 | 40.0k | ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override { |
97 | 40.0k | { |
98 | 40.0k | fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header)); |
99 | 40.0k | fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer)); |
100 | 40.0k | } |
101 | | |
102 | 40.0k | { |
103 | 40.0k | const auto numChannels = get_channels(); |
104 | 40.0k | const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32); |
105 | 136k | for (size_t i = 0; i < numChannels; i++) { |
106 | 96.5k | fuzzing::memory::memory_test(buffer[i], bytesPerChannel); |
107 | 96.5k | } |
108 | 40.0k | } |
109 | | |
110 | | /* Data is checked, now pass it towards encoder */ |
111 | 40.0k | if(encoder.get_state() == FLAC__STREAM_ENCODER_OK) { |
112 | 40.0k | if(encoder.get_channels() != get_channels()) |
113 | 45 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
114 | 40.0k | if(encoder.get_bits_per_sample() != get_bits_per_sample()) |
115 | 17 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
116 | 39.9k | encoder.process(buffer, frame->header.blocksize); |
117 | 39.9k | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
118 | 40.0k | } |
119 | 0 | else |
120 | 0 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
121 | 40.0k | } |
122 | 60.7k | void error_callback(::FLAC__StreamDecoderErrorStatus status) override { |
123 | 60.7k | fuzzing::memory::memory_test(status); |
124 | 60.7k | } |
125 | | }; |
126 | | } |
127 | | } |
128 | | |
129 | 7.79k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
130 | 7.79k | fuzzing::datasource::Datasource ds(data, size); |
131 | 7.79k | FLAC::Encoder::FuzzerStream encoder(ds); |
132 | 7.79k | FLAC::Decoder::FuzzerDecoder decoder(ds, encoder); |
133 | | |
134 | 7.79k | try { |
135 | 7.79k | const int channels = ds.Get<uint8_t>(); |
136 | 7.79k | const int bps = ds.Get<uint8_t>(); |
137 | 7.79k | encoder.set_channels(channels); |
138 | 7.79k | encoder.set_bits_per_sample(bps); |
139 | | |
140 | 7.79k | { |
141 | 7.79k | const bool res = encoder.set_streamable_subset(ds.Get<bool>()); |
142 | 7.79k | fuzzing::memory::memory_test(res); |
143 | 7.79k | } |
144 | 7.79k | { |
145 | 7.79k | const bool res = encoder.set_ogg_serial_number(ds.Get<long>()); |
146 | 7.79k | fuzzing::memory::memory_test(res); |
147 | 7.79k | } |
148 | 7.79k | { |
149 | 7.79k | const bool res = encoder.set_verify(ds.Get<bool>()); |
150 | 7.79k | fuzzing::memory::memory_test(res); |
151 | 7.79k | } |
152 | 7.79k | { |
153 | 7.79k | const bool res = encoder.set_compression_level(ds.Get<uint8_t>()); |
154 | 7.79k | fuzzing::memory::memory_test(res); |
155 | 7.79k | } |
156 | 7.79k | { |
157 | 7.79k | const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>()); |
158 | 7.79k | fuzzing::memory::memory_test(res); |
159 | 7.79k | } |
160 | 7.79k | { |
161 | 7.79k | const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>()); |
162 | 7.79k | fuzzing::memory::memory_test(res); |
163 | 7.79k | } |
164 | 7.79k | { |
165 | 7.79k | const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>()); |
166 | 7.79k | fuzzing::memory::memory_test(res); |
167 | 7.79k | } |
168 | 7.79k | { |
169 | 7.79k | const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>()); |
170 | 7.79k | fuzzing::memory::memory_test(res); |
171 | 7.79k | } |
172 | 7.79k | { |
173 | 7.79k | const bool res = encoder.set_do_escape_coding(ds.Get<bool>()); |
174 | 7.79k | fuzzing::memory::memory_test(res); |
175 | 7.79k | } |
176 | 7.79k | { |
177 | 7.79k | const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>()); |
178 | 7.79k | fuzzing::memory::memory_test(res); |
179 | 7.79k | } |
180 | 7.79k | { |
181 | 7.79k | const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>()); |
182 | 7.79k | fuzzing::memory::memory_test(res); |
183 | 7.79k | } |
184 | 7.79k | { |
185 | 7.79k | const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>()); |
186 | 7.79k | fuzzing::memory::memory_test(res); |
187 | 7.79k | } |
188 | 7.79k | { |
189 | 7.79k | const bool res = encoder.set_blocksize(ds.Get<uint16_t>()); |
190 | 7.79k | fuzzing::memory::memory_test(res); |
191 | 7.79k | } |
192 | 7.79k | { |
193 | 7.79k | const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>()); |
194 | 7.79k | fuzzing::memory::memory_test(res); |
195 | 7.79k | } |
196 | 7.79k | { |
197 | 7.79k | const bool res = encoder.set_sample_rate(ds.Get<uint32_t>()); |
198 | 7.79k | fuzzing::memory::memory_test(res); |
199 | 7.79k | } |
200 | 7.79k | { |
201 | 7.79k | const bool res = encoder.set_num_threads(ds.Get<uint32_t>()); |
202 | 7.79k | fuzzing::memory::memory_test(res); |
203 | 7.79k | } |
204 | | |
205 | 7.79k | decoder.set_metadata_respond_all(); |
206 | | |
207 | 7.79k | { |
208 | 7.79k | ::FLAC__StreamDecoderInitStatus ret; |
209 | 7.79k | if ( ds.Get<bool>() ) { |
210 | 6.72k | ret = decoder.init(); |
211 | 6.72k | } else { |
212 | 1.07k | ret = decoder.init_ogg(); |
213 | 1.07k | } |
214 | | |
215 | 7.79k | if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) { |
216 | 0 | goto end; |
217 | 0 | } |
218 | | |
219 | 7.79k | decoder.process_until_end_of_metadata(); |
220 | 7.79k | if(decoder.num_metadata_blocks > 0) |
221 | 898 | encoder.set_metadata(decoder.metadata_blocks, decoder.num_metadata_blocks); |
222 | 7.79k | } |
223 | | |
224 | 0 | { |
225 | 7.79k | ::FLAC__StreamEncoderInitStatus ret; |
226 | 7.79k | if ( ds.Get<bool>() ) { |
227 | 2.79k | ret = encoder.init(); |
228 | 5.00k | } else { |
229 | 5.00k | ret = encoder.init_ogg(); |
230 | 5.00k | } |
231 | | |
232 | 7.79k | if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) { |
233 | 696 | goto end; |
234 | 696 | } |
235 | 7.79k | } |
236 | | |
237 | | /* These sets must fail, because encoder is already initialized */ |
238 | 7.10k | { |
239 | 7.10k | bool res = false; |
240 | 7.10k | res = res || encoder.set_streamable_subset(true); |
241 | 7.10k | res = res || encoder.set_ogg_serial_number(0); |
242 | 7.10k | res = res || encoder.set_verify(true); |
243 | 7.10k | res = res || encoder.set_compression_level(0); |
244 | 7.10k | res = res || encoder.set_do_exhaustive_model_search(true); |
245 | 7.10k | res = res || encoder.set_do_mid_side_stereo(true); |
246 | 7.10k | res = res || encoder.set_loose_mid_side_stereo(true); |
247 | 7.10k | res = res || encoder.set_apodization("test"); |
248 | 7.10k | res = res || encoder.set_max_lpc_order(0); |
249 | 7.10k | res = res || encoder.set_qlp_coeff_precision(0); |
250 | 7.10k | res = res || encoder.set_do_qlp_coeff_prec_search(true); |
251 | 7.10k | res = res || encoder.set_do_escape_coding(true); |
252 | 7.10k | res = res || encoder.set_min_residual_partition_order(0); |
253 | 7.10k | res = res || encoder.set_max_residual_partition_order(0); |
254 | 7.10k | res = res || encoder.set_rice_parameter_search_dist(0); |
255 | 7.10k | res = res || encoder.set_total_samples_estimate(0); |
256 | 7.10k | res = res || encoder.set_channels(channels); |
257 | 7.10k | res = res || encoder.set_bits_per_sample(16); |
258 | 7.10k | res = res || encoder.set_limit_min_bitrate(true); |
259 | 7.10k | res = res || encoder.set_blocksize(3021); |
260 | 7.10k | res = res || encoder.set_sample_rate(44100); |
261 | 7.10k | res = res || (encoder.set_num_threads(4) == FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK); |
262 | 7.10k | fuzzing::memory::memory_test(res); |
263 | 7.10k | if(res) |
264 | 0 | abort(); |
265 | 7.10k | } |
266 | | |
267 | | |
268 | 7.10k | { |
269 | | /* XORing values as otherwise compiler will optimize, apparently */ |
270 | 7.10k | bool res = false; |
271 | 7.10k | res = res != encoder.get_streamable_subset(); |
272 | 7.10k | res = res != encoder.get_verify(); |
273 | 7.10k | res = res != encoder.get_do_exhaustive_model_search(); |
274 | 7.10k | res = res != encoder.get_do_mid_side_stereo(); |
275 | 7.10k | res = res != encoder.get_loose_mid_side_stereo(); |
276 | 7.10k | res = res != encoder.get_max_lpc_order(); |
277 | 7.10k | res = res != encoder.get_qlp_coeff_precision(); |
278 | 7.10k | res = res != encoder.get_do_qlp_coeff_prec_search(); |
279 | 7.10k | res = res != encoder.get_do_escape_coding(); |
280 | 7.10k | res = res != encoder.get_min_residual_partition_order(); |
281 | 7.10k | res = res != encoder.get_max_residual_partition_order(); |
282 | 7.10k | res = res != encoder.get_rice_parameter_search_dist(); |
283 | 7.10k | res = res != encoder.get_total_samples_estimate(); |
284 | 7.10k | res = res != encoder.get_channels(); |
285 | 7.10k | res = res != encoder.get_bits_per_sample(); |
286 | 7.10k | res = res != encoder.get_limit_min_bitrate(); |
287 | 7.10k | res = res != encoder.get_blocksize(); |
288 | 7.10k | res = res != encoder.get_sample_rate(); |
289 | 7.10k | res = res != encoder.get_num_threads(); |
290 | 7.10k | fuzzing::memory::memory_test(res); |
291 | 7.10k | } |
292 | | |
293 | 7.10k | decoder.process_until_end_of_stream(); |
294 | | |
295 | 7.10k | } catch ( ... ) { } |
296 | | |
297 | 7.79k | end: |
298 | 7.79k | { |
299 | 7.79k | const bool res = encoder.finish(); |
300 | 7.79k | fuzzing::memory::memory_test(res); |
301 | 7.79k | } |
302 | 7.79k | { |
303 | 7.79k | const bool res = decoder.finish(); |
304 | 7.79k | fuzzing::memory::memory_test(res); |
305 | 7.79k | } |
306 | 47.6k | for(int i = 0; i < decoder.num_metadata_blocks; i++) |
307 | 39.8k | FLAC__metadata_object_delete(decoder.metadata_blocks[i]); |
308 | | |
309 | 7.79k | return 0; |
310 | 7.79k | } |