Coverage Report

Created: 2026-01-10 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flac/oss-fuzz/decoder.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
27
#include <fuzzing/datasource/datasource.hpp>
28
#include <fuzzing/memory.hpp>
29
30
#include "FLAC++/decoder.h"
31
#include "FLAC++/metadata.h"
32
#include "common.h"
33
34
189
template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) {
35
189
    (void)id;
36
189
    switch ( Get<uint8_t>() ) {
37
34
        case 0:
38
34
            return FLAC__METADATA_TYPE_STREAMINFO;
39
15
        case 1:
40
15
            return FLAC__METADATA_TYPE_PADDING;
41
4
        case 2:
42
4
            return FLAC__METADATA_TYPE_APPLICATION;
43
5
        case 3:
44
5
            return FLAC__METADATA_TYPE_SEEKTABLE;
45
2
        case 4:
46
2
            return FLAC__METADATA_TYPE_VORBIS_COMMENT;
47
7
        case 5:
48
7
            return FLAC__METADATA_TYPE_CUESHEET;
49
1
        case 6:
50
1
            return FLAC__METADATA_TYPE_PICTURE;
51
7
        case 7:
52
7
            return FLAC__METADATA_TYPE_UNDEFINED;
53
3
        case 8:
54
3
            return FLAC__MAX_METADATA_TYPE;
55
109
        default:
56
109
            return FLAC__METADATA_TYPE_STREAMINFO;
57
189
    }
58
189
}
59
60
namespace FLAC {
61
  namespace Decoder {
62
        class FuzzerStream : public Stream {
63
            private:
64
                fuzzing::datasource::Datasource& ds;
65
            public:
66
                FuzzerStream(fuzzing::datasource::Datasource& dsrc) :
67
7.83k
                    Stream(), ds(dsrc) { }
68
69
267k
                ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)  override {
70
267k
                    try {
71
267k
                        const size_t maxCopySize = *bytes;
72
73
267k
                        if ( maxCopySize > 0 ) {
74
                            /* memset just to test if this overwrites anything, and triggers ASAN */
75
267k
                            memset(buffer, 0, maxCopySize);
76
267k
                        }
77
78
267k
                        const auto data = ds.GetData(0);
79
267k
                        const auto dataSize = data.size();
80
267k
                        const auto copySize = std::min(maxCopySize, dataSize);
81
82
267k
                        if ( copySize > 0 ) {
83
70.6k
                            memcpy(buffer, data.data(), copySize);
84
70.6k
                        }
85
86
267k
                        *bytes = copySize;
87
88
267k
                        return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
89
267k
                    } catch ( ... ) {
90
55.0k
                      return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
91
55.0k
                    }
92
267k
                }
93
94
84.5k
                ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])  override {
95
84.5k
                    {
96
84.5k
                        fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header));
97
84.5k
                        fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer));
98
84.5k
                    }
99
100
84.5k
                    {
101
84.5k
                        const auto numChannels = get_channels();
102
84.5k
                        const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32);
103
241k
                        for (size_t i = 0; i < numChannels; i++) {
104
156k
                            fuzzing::memory::memory_test(buffer[i], bytesPerChannel);
105
156k
                        }
106
84.5k
                    }
107
108
84.5k
                    try {
109
84.5k
                        if ( ds.Get<bool>() == true ) {
110
680
                          return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
111
680
                        }
112
84.5k
                    } catch ( ... ) { }
113
83.9k
                    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
114
84.5k
                }
115
116
243k
                void error_callback(::FLAC__StreamDecoderErrorStatus status)  override {
117
243k
                    fuzzing::memory::memory_test(status);
118
243k
                }
119
120
22.8k
                void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
121
22.8k
                    Metadata::Prototype * cloned_object = nullptr;
122
22.8k
                    fuzzing::memory::memory_test(metadata->type);
123
22.8k
                    fuzzing::memory::memory_test(metadata->is_last);
124
22.8k
                    fuzzing::memory::memory_test(metadata->length);
125
22.8k
                    fuzzing::memory::memory_test(metadata->data);
126
22.8k
                    if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
127
1.20k
                        cloned_object = new Metadata::StreamInfo(metadata);
128
21.6k
                    else if (metadata->type == FLAC__METADATA_TYPE_PADDING)
129
354
                        cloned_object = new Metadata::Padding(metadata);
130
21.2k
                    else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION)
131
1.45k
                        cloned_object = new Metadata::Application(metadata);
132
19.8k
                    else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE)
133
1.83k
                        cloned_object = new Metadata::SeekTable(metadata);
134
17.9k
                    else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
135
1.50k
                        cloned_object = new Metadata::VorbisComment(metadata);
136
16.4k
                    else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET)
137
4.85k
                        cloned_object = new Metadata::CueSheet(metadata);
138
11.6k
                    else if (metadata->type == FLAC__METADATA_TYPE_PICTURE)
139
7.98k
                        cloned_object = new Metadata::Picture(metadata);
140
3.63k
                    else
141
3.63k
                        return;
142
19.2k
                    if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) {
143
19.1k
                        if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE)
144
1.83k
                            dynamic_cast<Metadata::SeekTable *>(cloned_object)->is_legal();
145
19.1k
                        if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE)
146
7.91k
                            dynamic_cast<Metadata::Picture *>(cloned_object)->is_legal(NULL);
147
19.1k
                        if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET)
148
4.85k
                            dynamic_cast<Metadata::CueSheet *>(cloned_object)->is_legal(true,NULL);
149
19.1k
                    }
150
19.2k
                    delete cloned_object;
151
19.2k
                }
152
153
71.4k
                ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override {
154
71.4k
                    fuzzing::memory::memory_test(absolute_byte_offset);
155
156
71.4k
                    try {
157
71.4k
                        if ( ds.Get<bool>() == true ) {
158
67.3k
                            return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
159
67.3k
                        } else {
160
4.12k
                            return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
161
4.12k
                        }
162
71.4k
                    } catch ( ... ) {
163
31
                        return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
164
31
                    }
165
71.4k
                }
166
#if 0
167
                ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override {
168
                    fuzzing::memory::memory_test(*absolute_byte_offset);
169
170
                    try {
171
                        if ( ds.Get<bool>() == true ) {
172
                            return FLAC__STREAM_DECODER_TELL_STATUS_OK;
173
                        } else {
174
                            return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
175
                        }
176
                    } catch ( ... ) {
177
                        return FLAC__STREAM_DECODER_TELL_STATUS_OK;
178
                    }
179
                }
180
181
                ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override {
182
                    fuzzing::memory::memory_test(*stream_length);
183
184
                    try {
185
                        if ( ds.Get<bool>() == true ) {
186
                            return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
187
                        } else {
188
                            return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
189
                        }
190
                    } catch ( ... ) {
191
                        return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
192
                    }
193
                }
194
#endif
195
        };
196
    }
197
}
198
199
7.83k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
200
7.83k
    fuzzing::datasource::Datasource ds(data, size);
201
7.83k
    FLAC::Decoder::FuzzerStream decoder(ds);
202
7.83k
    bool use_ogg = true;
203
204
7.83k
    try {
205
7.83k
        if ( ds.Get<bool>() ) {
206
6.81k
            use_ogg = false;
207
6.81k
        }
208
209
7.83k
        decoder.set_decode_chained_stream(true);
210
211
7.83k
        if ( ds.Get<bool>() ) {
212
#ifdef FUZZER_DEBUG
213
            printf("set_ogg_serial_number\n");
214
#endif
215
36
            decoder.set_ogg_serial_number(ds.Get<long>());
216
36
        }
217
7.83k
        if ( ds.Get<bool>() ) {
218
#ifdef FUZZER_DEBUG
219
            printf("set_md5_checking\n");
220
#endif
221
1.34k
            decoder.set_md5_checking(ds.Get<bool>());
222
1.34k
        }
223
7.83k
        if ( ds.Get<bool>() ) {
224
#ifdef FUZZER_DEBUG
225
            printf("set_metadata_respond\n");
226
#endif
227
78
            decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>());
228
78
        }
229
7.83k
        if ( ds.Get<bool>() ) {
230
55
            const auto idVector = ds.GetData(0);
231
55
            unsigned char id[4];
232
55
            if ( idVector.size() >= sizeof(id) ) {
233
17
                memcpy(id, idVector.data(), sizeof(id));
234
#ifdef FUZZER_DEBUG
235
                printf("set_metadata_respond_application\n");
236
#endif
237
17
                decoder.set_metadata_respond_application(id);
238
17
            }
239
55
        }
240
7.83k
        if ( ds.Get<bool>() ) {
241
#ifdef FUZZER_DEBUG
242
            printf("set_metadata_respond_all\n");
243
#endif
244
4.30k
            decoder.set_metadata_respond_all();
245
4.30k
        }
246
7.83k
        if ( ds.Get<bool>() ) {
247
#ifdef FUZZER_DEBUG
248
            printf("set_metadata_ignore\n");
249
#endif
250
111
            decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>());
251
111
        }
252
7.83k
        if ( ds.Get<bool>() ) {
253
64
            const auto idVector = ds.GetData(0);
254
64
            unsigned char id[4];
255
64
            if ( idVector.size() >= sizeof(id) ) {
256
56
                memcpy(id, idVector.data(), sizeof(id));
257
#ifdef FUZZER_DEBUG
258
                printf("set_metadata_ignore_application\n");
259
#endif
260
56
                decoder.set_metadata_ignore_application(id);
261
56
            }
262
64
        }
263
7.83k
        if ( ds.Get<bool>() ) {
264
#ifdef FUZZER_DEBUG
265
            printf("set_metadata_ignore_all\n");
266
#endif
267
2.60k
            decoder.set_metadata_ignore_all();
268
2.60k
        }
269
7.83k
        {
270
7.83k
            ::FLAC__StreamDecoderInitStatus ret;
271
7.83k
            if ( !use_ogg ) {
272
6.73k
                ret = decoder.init();
273
6.73k
            } else {
274
1.09k
                ret = decoder.init_ogg();
275
1.09k
            }
276
277
7.83k
            if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
278
0
                goto end;
279
0
            }
280
7.83k
        }
281
282
258k
        while ( ds.Get<bool>() ) {
283
250k
            switch ( ds.Get<uint8_t>() ) {
284
13.0k
                case    0:
285
13.0k
                    {
286
#ifdef FUZZER_DEBUG
287
                        printf("flush\n");
288
#endif
289
13.0k
                        const bool res = decoder.flush();
290
13.0k
                        fuzzing::memory::memory_test(res);
291
13.0k
                    }
292
13.0k
                    break;
293
71.7k
                case    1:
294
71.7k
                    {
295
#ifdef FUZZER_DEBUG
296
                        printf("reset\n");
297
#endif
298
71.7k
                        const bool res = decoder.reset();
299
71.7k
                        fuzzing::memory::memory_test(res);
300
71.7k
                    }
301
71.7k
                    break;
302
15.9k
                case    2:
303
15.9k
                    {
304
#ifdef FUZZER_DEBUG
305
                        printf("process_single\n");
306
#endif
307
15.9k
                        const bool res = decoder.process_single();
308
15.9k
                        fuzzing::memory::memory_test(res);
309
15.9k
                    }
310
15.9k
                    break;
311
74.0k
                case    3:
312
74.0k
                    {
313
#ifdef FUZZER_DEBUG
314
                        printf("process_until_end_of_metadata\n");
315
#endif
316
74.0k
                        const bool res = decoder.process_until_end_of_metadata();
317
74.0k
                        fuzzing::memory::memory_test(res);
318
74.0k
                    }
319
74.0k
                    break;
320
25.7k
                case    4:
321
25.7k
                    {
322
#ifdef FUZZER_DEBUG
323
                        printf("process_until_end_of_stream\n");
324
#endif
325
25.7k
                        const bool res = decoder.process_until_end_of_stream();
326
25.7k
                        fuzzing::memory::memory_test(res);
327
25.7k
                    }
328
25.7k
                    break;
329
2.24k
                case    5:
330
2.24k
                    {
331
#ifdef FUZZER_DEBUG
332
                        printf("skip_single_frame\n");
333
#endif
334
2.24k
                        const bool res = decoder.skip_single_frame();
335
2.24k
                        fuzzing::memory::memory_test(res);
336
2.24k
                    }
337
2.24k
                    break;
338
871
                case    6:
339
871
                    {
340
#ifdef FUZZER_DEBUG
341
                        printf("seek_absolute\n");
342
#endif
343
871
                        const bool res = decoder.seek_absolute(ds.Get<uint64_t>());
344
871
                        fuzzing::memory::memory_test(res);
345
871
                    }
346
871
                    break;
347
245
                case    7:
348
245
                    {
349
#ifdef FUZZER_DEBUG
350
                        printf("get_md5_checking\n");
351
#endif
352
245
                        const bool res = decoder.get_md5_checking();
353
245
                        fuzzing::memory::memory_test(res);
354
245
                    }
355
245
                    break;
356
821
                case    8:
357
821
                    {
358
#ifdef FUZZER_DEBUG
359
                        printf("get_total_samples\n");
360
#endif
361
821
                        const bool res = decoder.get_total_samples();
362
821
                        fuzzing::memory::memory_test(res);
363
821
                    }
364
821
                    break;
365
459
                case    9:
366
459
                    {
367
#ifdef FUZZER_DEBUG
368
                        printf("get_channels\n");
369
#endif
370
459
                        const bool res = decoder.get_channels();
371
459
                        fuzzing::memory::memory_test(res);
372
459
                    }
373
459
                    break;
374
1.14k
                case    10:
375
1.14k
                    {
376
#ifdef FUZZER_DEBUG
377
                        printf("get_bits_per_sample\n");
378
#endif
379
1.14k
                        const bool res = decoder.get_bits_per_sample();
380
1.14k
                        fuzzing::memory::memory_test(res);
381
1.14k
                    }
382
1.14k
                    break;
383
478
                case    11:
384
478
                    {
385
#ifdef FUZZER_DEBUG
386
                        printf("get_sample_rate\n");
387
#endif
388
478
                        const bool res = decoder.get_sample_rate();
389
478
                        fuzzing::memory::memory_test(res);
390
478
                    }
391
478
                    break;
392
214
                case    12:
393
214
                    {
394
#ifdef FUZZER_DEBUG
395
                        printf("get_blocksize\n");
396
#endif
397
214
                        const bool res = decoder.get_blocksize();
398
214
                        fuzzing::memory::memory_test(res);
399
214
                    }
400
214
                    break;
401
250k
            }
402
250k
        }
403
7.83k
    } catch ( ... ) { }
404
405
7.83k
end:
406
7.83k
    {
407
7.83k
        const bool res = decoder.finish();
408
7.83k
        fuzzing::memory::memory_test(res);
409
7.83k
    }
410
7.83k
    return 0;
411
7.83k
}