xref: /aosp_15_r20/external/flac/oss-fuzz/encoder.cc (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
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:
FuzzerStream(fuzzing::datasource::Datasource &)40                 FuzzerStream(fuzzing::datasource::Datasource&) :
41                     Stream() { }
42 
write_callback(const FLAC__byte buffer[],size_t bytes,uint32_t,uint32_t)43                 ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override {
44                     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                     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
53                 }
54         };
55     }
56 }
57 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)58 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
59     fuzzing::datasource::Datasource ds(data, size);
60     FLAC::Encoder::FuzzerStream encoder(ds);
61 
62     try {
63             const int channels = ds.Get<uint8_t>();
64             const int bps = ds.Get<uint8_t>();
65             encoder.set_channels(channels);
66             encoder.set_bits_per_sample(bps);
67 
68         {
69             const bool res = encoder.set_streamable_subset(ds.Get<bool>());
70             fuzzing::memory::memory_test(res);
71         }
72         {
73             const bool res = encoder.set_ogg_serial_number(ds.Get<long>());
74             fuzzing::memory::memory_test(res);
75         }
76         {
77             const bool res = encoder.set_verify(ds.Get<bool>());
78             fuzzing::memory::memory_test(res);
79         }
80         {
81             const bool res = encoder.set_compression_level(ds.Get<uint8_t>());
82             fuzzing::memory::memory_test(res);
83         }
84         {
85             const bool res = encoder.set_do_exhaustive_model_search(ds.Get<bool>());
86             fuzzing::memory::memory_test(res);
87         }
88         {
89             const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>());
90             fuzzing::memory::memory_test(res);
91         }
92         {
93             const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>());
94             fuzzing::memory::memory_test(res);
95         }
96         {
97             const auto s = ds.Get<std::string>();
98             const bool res = encoder.set_apodization(s.data());
99             fuzzing::memory::memory_test(res);
100         }
101         {
102             const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>());
103             fuzzing::memory::memory_test(res);
104         }
105         {
106             const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>());
107             fuzzing::memory::memory_test(res);
108         }
109         {
110             const bool res = encoder.set_do_qlp_coeff_prec_search(ds.Get<bool>());
111             fuzzing::memory::memory_test(res);
112         }
113         {
114             const bool res = encoder.set_do_escape_coding(ds.Get<bool>());
115             fuzzing::memory::memory_test(res);
116         }
117         {
118             const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>());
119             fuzzing::memory::memory_test(res);
120         }
121         {
122             const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>());
123             fuzzing::memory::memory_test(res);
124         }
125         {
126             const bool res = encoder.set_rice_parameter_search_dist(ds.Get<uint32_t>());
127             fuzzing::memory::memory_test(res);
128         }
129         {
130             const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>());
131             fuzzing::memory::memory_test(res);
132         }
133         {
134             const bool res = encoder.set_blocksize(ds.Get<uint16_t>());
135             fuzzing::memory::memory_test(res);
136         }
137         {
138             const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>());
139             fuzzing::memory::memory_test(res);
140         }
141         {
142             const bool res = encoder.set_sample_rate(ds.Get<uint32_t>());
143             fuzzing::memory::memory_test(res);
144         }
145 
146         if ( size > 2 * 65535 * 4 ) {
147             /* With large inputs and expensive options enabled, the fuzzer can get *really* slow.
148             * Some combinations can make the fuzzer timeout (>60 seconds). However, while combining
149             * options makes the fuzzer slower, most options do not expose new code when combined.
150             * Therefore, combining slow options is disabled for large inputs. Any input containing
151             * more than 65536 * 2 samples of 32 bits each (max blocksize, stereo) is considered large
152             */
153             encoder.set_do_qlp_coeff_prec_search(false);
154             encoder.set_do_exhaustive_model_search(false);
155         }
156         if ( size > 2 * 4096 * 4 + 250 ) {
157             /* With subdivide_tukey in the mix testing apodizations can get really expensive. Therefore
158              * this is disabled for inputs of more than one whole stereo block of 32-bit inputs plus a
159              * bit of overhead */
160             encoder.set_apodization("");
161         }
162 
163         {
164             ::FLAC__StreamEncoderInitStatus ret;
165             if ( ds.Get<bool>() ) {
166                 ret = encoder.init();
167             } else {
168                 ret = encoder.init_ogg();
169             }
170 
171             if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) {
172                 goto end;
173             }
174         }
175 
176 	/* These sets must fail, because encoder is already initialized */
177         {
178             bool res = false;
179             res = res || encoder.set_streamable_subset(true);
180             res = res || encoder.set_ogg_serial_number(0);
181             res = res || encoder.set_verify(true);
182             res = res || encoder.set_compression_level(0);
183             res = res || encoder.set_do_exhaustive_model_search(true);
184             res = res || encoder.set_do_mid_side_stereo(true);
185             res = res || encoder.set_loose_mid_side_stereo(true);
186             res = res || encoder.set_apodization("test");
187             res = res || encoder.set_max_lpc_order(0);
188             res = res || encoder.set_qlp_coeff_precision(0);
189             res = res || encoder.set_do_qlp_coeff_prec_search(true);
190             res = res || encoder.set_do_escape_coding(true);
191             res = res || encoder.set_min_residual_partition_order(0);
192             res = res || encoder.set_max_residual_partition_order(0);
193             res = res || encoder.set_rice_parameter_search_dist(0);
194             res = res || encoder.set_total_samples_estimate(0);
195             res = res || encoder.set_channels(channels);
196             res = res || encoder.set_bits_per_sample(16);
197             res = res || encoder.set_limit_min_bitrate(true);
198             res = res || encoder.set_blocksize(3021);
199             res = res || encoder.set_sample_rate(44100);
200             fuzzing::memory::memory_test(res);
201             if(res)
202                 abort();
203         }
204 
205 
206         {
207             /* XORing values as otherwise compiler will optimize, apparently */
208             bool res = false;
209             res = res != encoder.get_streamable_subset();
210             res = res != encoder.get_verify();
211             res = res != encoder.get_do_exhaustive_model_search();
212             res = res != encoder.get_do_mid_side_stereo();
213             res = res != encoder.get_loose_mid_side_stereo();
214             res = res != encoder.get_max_lpc_order();
215             res = res != encoder.get_qlp_coeff_precision();
216             res = res != encoder.get_do_qlp_coeff_prec_search();
217             res = res != encoder.get_do_escape_coding();
218             res = res != encoder.get_min_residual_partition_order();
219             res = res != encoder.get_max_residual_partition_order();
220             res = res != encoder.get_rice_parameter_search_dist();
221             res = res != encoder.get_total_samples_estimate();
222             res = res != encoder.get_channels();
223             res = res != encoder.get_bits_per_sample();
224             res = res != encoder.get_limit_min_bitrate();
225             res = res != encoder.get_blocksize();
226             res = res != encoder.get_sample_rate();
227             fuzzing::memory::memory_test(res);
228         }
229 
230 
231         while ( ds.Get<bool>() ) {
232             {
233                 auto dat = ds.GetVector<FLAC__int32>();
234 
235                 if( ds.Get<bool>() )
236                     /* Mask */
237                     for (size_t i = 0; i < dat.size(); i++)
238 			/* If we get here, bps is 4 or larger, or init will have failed */
239                         dat[i] = (int32_t)(((uint32_t)(dat[i]) << (32-bps)) >> (32-bps));
240 
241                 const uint32_t samples = dat.size() / channels;
242                 if ( samples > 0 ) {
243                     const int32_t* ptr = dat.data();
244                     const bool res = encoder.process_interleaved(ptr, samples);
245                     fuzzing::memory::memory_test(res);
246                 }
247             }
248         }
249     } catch ( ... ) { }
250 
251 end:
252     {
253         const bool res = encoder.finish();
254         fuzzing::memory::memory_test(res);
255     }
256     return 0;
257 }
258