Coverage Report

Created: 2025-11-01 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
137
template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) {
35
137
    (void)id;
36
137
    switch ( Get<uint8_t>() ) {
37
20
        case 0:
38
20
            return FLAC__METADATA_TYPE_STREAMINFO;
39
11
        case 1:
40
11
            return FLAC__METADATA_TYPE_PADDING;
41
5
        case 2:
42
5
            return FLAC__METADATA_TYPE_APPLICATION;
43
5
        case 3:
44
5
            return FLAC__METADATA_TYPE_SEEKTABLE;
45
1
        case 4:
46
1
            return FLAC__METADATA_TYPE_VORBIS_COMMENT;
47
4
        case 5:
48
4
            return FLAC__METADATA_TYPE_CUESHEET;
49
0
        case 6:
50
0
            return FLAC__METADATA_TYPE_PICTURE;
51
4
        case 7:
52
4
            return FLAC__METADATA_TYPE_UNDEFINED;
53
4
        case 8:
54
4
            return FLAC__MAX_METADATA_TYPE;
55
81
        default:
56
81
            return FLAC__METADATA_TYPE_STREAMINFO;
57
137
    }
58
137
}
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
8.95k
                    Stream(), ds(dsrc) { }
68
69
157k
                ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)  override {
70
157k
                    try {
71
157k
                        const size_t maxCopySize = *bytes;
72
73
157k
                        if ( maxCopySize > 0 ) {
74
                            /* memset just to test if this overwrites anything, and triggers ASAN */
75
157k
                            memset(buffer, 0, maxCopySize);
76
157k
                        }
77
78
157k
                        const auto data = ds.GetData(0);
79
157k
                        const auto dataSize = data.size();
80
157k
                        const auto copySize = std::min(maxCopySize, dataSize);
81
82
157k
                        if ( copySize > 0 ) {
83
82.3k
                            memcpy(buffer, data.data(), copySize);
84
82.3k
                        }
85
86
157k
                        *bytes = copySize;
87
88
157k
                        return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
89
157k
                    } catch ( ... ) {
90
61.1k
                      return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
91
61.1k
                    }
92
157k
                }
93
94
74.6k
                ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])  override {
95
74.6k
                    {
96
74.6k
                        fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header));
97
74.6k
                        fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer));
98
74.6k
                    }
99
100
74.6k
                    {
101
74.6k
                        const auto numChannels = get_channels();
102
74.6k
                        const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32);
103
220k
                        for (size_t i = 0; i < numChannels; i++) {
104
145k
                            fuzzing::memory::memory_test(buffer[i], bytesPerChannel);
105
145k
                        }
106
74.6k
                    }
107
108
74.6k
                    try {
109
74.6k
                        if ( ds.Get<bool>() == true ) {
110
879
                          return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
111
879
                        }
112
74.6k
                    } catch ( ... ) { }
113
73.7k
                    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
114
74.6k
                }
115
116
259k
                void error_callback(::FLAC__StreamDecoderErrorStatus status)  override {
117
259k
                    fuzzing::memory::memory_test(status);
118
259k
                }
119
120
26.3k
                void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
121
26.3k
                    Metadata::Prototype * cloned_object = nullptr;
122
26.3k
                    fuzzing::memory::memory_test(metadata->type);
123
26.3k
                    fuzzing::memory::memory_test(metadata->is_last);
124
26.3k
                    fuzzing::memory::memory_test(metadata->length);
125
26.3k
                    fuzzing::memory::memory_test(metadata->data);
126
26.3k
                    if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
127
1.86k
                        cloned_object = new Metadata::StreamInfo(metadata);
128
24.4k
                    else if (metadata->type == FLAC__METADATA_TYPE_PADDING)
129
922
                        cloned_object = new Metadata::Padding(metadata);
130
23.5k
                    else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION)
131
3.31k
                        cloned_object = new Metadata::Application(metadata);
132
20.2k
                    else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE)
133
1.71k
                        cloned_object = new Metadata::SeekTable(metadata);
134
18.5k
                    else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
135
1.67k
                        cloned_object = new Metadata::VorbisComment(metadata);
136
16.8k
                    else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET)
137
4.53k
                        cloned_object = new Metadata::CueSheet(metadata);
138
12.2k
                    else if (metadata->type == FLAC__METADATA_TYPE_PICTURE)
139
8.35k
                        cloned_object = new Metadata::Picture(metadata);
140
3.93k
                    else
141
3.93k
                        return;
142
22.3k
                    if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) {
143
22.3k
                        if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE)
144
1.71k
                            dynamic_cast<Metadata::SeekTable *>(cloned_object)->is_legal();
145
22.3k
                        if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE)
146
8.28k
                            dynamic_cast<Metadata::Picture *>(cloned_object)->is_legal(NULL);
147
22.3k
                        if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET)
148
4.53k
                            dynamic_cast<Metadata::CueSheet *>(cloned_object)->is_legal(true,NULL);
149
22.3k
                    }
150
22.3k
                    delete cloned_object;
151
22.3k
                }
152
153
84.8k
                ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override {
154
84.8k
                    fuzzing::memory::memory_test(absolute_byte_offset);
155
156
84.8k
                    try {
157
84.8k
                        if ( ds.Get<bool>() == true ) {
158
80.5k
                            return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
159
80.5k
                        } else {
160
4.31k
                            return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
161
4.31k
                        }
162
84.8k
                    } catch ( ... ) {
163
34
                        return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
164
34
                    }
165
84.8k
                }
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
8.95k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
200
8.95k
    fuzzing::datasource::Datasource ds(data, size);
201
8.95k
    FLAC::Decoder::FuzzerStream decoder(ds);
202
8.95k
    bool use_ogg = true;
203
204
8.95k
    try {
205
8.95k
        if ( ds.Get<bool>() ) {
206
7.76k
            use_ogg = false;
207
7.76k
        }
208
209
8.95k
        decoder.set_decode_chained_stream(true);
210
211
8.95k
        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
8.95k
        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
8.95k
        if ( ds.Get<bool>() ) {
224
#ifdef FUZZER_DEBUG
225
            printf("set_metadata_respond\n");
226
#endif
227
59
            decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>());
228
59
        }
229
8.95k
        if ( ds.Get<bool>() ) {
230
60
            const auto idVector = ds.GetData(0);
231
60
            unsigned char id[4];
232
60
            if ( idVector.size() >= sizeof(id) ) {
233
18
                memcpy(id, idVector.data(), sizeof(id));
234
#ifdef FUZZER_DEBUG
235
                printf("set_metadata_respond_application\n");
236
#endif
237
18
                decoder.set_metadata_respond_application(id);
238
18
            }
239
60
        }
240
8.95k
        if ( ds.Get<bool>() ) {
241
#ifdef FUZZER_DEBUG
242
            printf("set_metadata_respond_all\n");
243
#endif
244
4.82k
            decoder.set_metadata_respond_all();
245
4.82k
        }
246
8.95k
        if ( ds.Get<bool>() ) {
247
#ifdef FUZZER_DEBUG
248
            printf("set_metadata_ignore\n");
249
#endif
250
78
            decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>());
251
78
        }
252
8.95k
        if ( ds.Get<bool>() ) {
253
71
            const auto idVector = ds.GetData(0);
254
71
            unsigned char id[4];
255
71
            if ( idVector.size() >= sizeof(id) ) {
256
63
                memcpy(id, idVector.data(), sizeof(id));
257
#ifdef FUZZER_DEBUG
258
                printf("set_metadata_ignore_application\n");
259
#endif
260
63
                decoder.set_metadata_ignore_application(id);
261
63
            }
262
71
        }
263
8.95k
        if ( ds.Get<bool>() ) {
264
#ifdef FUZZER_DEBUG
265
            printf("set_metadata_ignore_all\n");
266
#endif
267
3.06k
            decoder.set_metadata_ignore_all();
268
3.06k
        }
269
8.95k
        {
270
8.95k
            ::FLAC__StreamDecoderInitStatus ret;
271
8.95k
            if ( !use_ogg ) {
272
7.68k
                ret = decoder.init();
273
7.68k
            } else {
274
1.26k
                ret = decoder.init_ogg();
275
1.26k
            }
276
277
8.95k
            if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
278
0
                goto end;
279
0
            }
280
8.95k
        }
281
282
295k
        while ( ds.Get<bool>() ) {
283
286k
            switch ( ds.Get<uint8_t>() ) {
284
12.7k
                case    0:
285
12.7k
                    {
286
#ifdef FUZZER_DEBUG
287
                        printf("flush\n");
288
#endif
289
12.7k
                        const bool res = decoder.flush();
290
12.7k
                        fuzzing::memory::memory_test(res);
291
12.7k
                    }
292
12.7k
                    break;
293
85.1k
                case    1:
294
85.1k
                    {
295
#ifdef FUZZER_DEBUG
296
                        printf("reset\n");
297
#endif
298
85.1k
                        const bool res = decoder.reset();
299
85.1k
                        fuzzing::memory::memory_test(res);
300
85.1k
                    }
301
85.1k
                    break;
302
16.4k
                case    2:
303
16.4k
                    {
304
#ifdef FUZZER_DEBUG
305
                        printf("process_single\n");
306
#endif
307
16.4k
                        const bool res = decoder.process_single();
308
16.4k
                        fuzzing::memory::memory_test(res);
309
16.4k
                    }
310
16.4k
                    break;
311
84.0k
                case    3:
312
84.0k
                    {
313
#ifdef FUZZER_DEBUG
314
                        printf("process_until_end_of_metadata\n");
315
#endif
316
84.0k
                        const bool res = decoder.process_until_end_of_metadata();
317
84.0k
                        fuzzing::memory::memory_test(res);
318
84.0k
                    }
319
84.0k
                    break;
320
27.8k
                case    4:
321
27.8k
                    {
322
#ifdef FUZZER_DEBUG
323
                        printf("process_until_end_of_stream\n");
324
#endif
325
27.8k
                        const bool res = decoder.process_until_end_of_stream();
326
27.8k
                        fuzzing::memory::memory_test(res);
327
27.8k
                    }
328
27.8k
                    break;
329
1.77k
                case    5:
330
1.77k
                    {
331
#ifdef FUZZER_DEBUG
332
                        printf("skip_single_frame\n");
333
#endif
334
1.77k
                        const bool res = decoder.skip_single_frame();
335
1.77k
                        fuzzing::memory::memory_test(res);
336
1.77k
                    }
337
1.77k
                    break;
338
1.09k
                case    6:
339
1.09k
                    {
340
#ifdef FUZZER_DEBUG
341
                        printf("seek_absolute\n");
342
#endif
343
1.09k
                        const bool res = decoder.seek_absolute(ds.Get<uint64_t>());
344
1.09k
                        fuzzing::memory::memory_test(res);
345
1.09k
                    }
346
1.09k
                    break;
347
268
                case    7:
348
268
                    {
349
#ifdef FUZZER_DEBUG
350
                        printf("get_md5_checking\n");
351
#endif
352
268
                        const bool res = decoder.get_md5_checking();
353
268
                        fuzzing::memory::memory_test(res);
354
268
                    }
355
268
                    break;
356
807
                case    8:
357
807
                    {
358
#ifdef FUZZER_DEBUG
359
                        printf("get_total_samples\n");
360
#endif
361
807
                        const bool res = decoder.get_total_samples();
362
807
                        fuzzing::memory::memory_test(res);
363
807
                    }
364
807
                    break;
365
477
                case    9:
366
477
                    {
367
#ifdef FUZZER_DEBUG
368
                        printf("get_channels\n");
369
#endif
370
477
                        const bool res = decoder.get_channels();
371
477
                        fuzzing::memory::memory_test(res);
372
477
                    }
373
477
                    break;
374
1.57k
                case    10:
375
1.57k
                    {
376
#ifdef FUZZER_DEBUG
377
                        printf("get_bits_per_sample\n");
378
#endif
379
1.57k
                        const bool res = decoder.get_bits_per_sample();
380
1.57k
                        fuzzing::memory::memory_test(res);
381
1.57k
                    }
382
1.57k
                    break;
383
627
                case    11:
384
627
                    {
385
#ifdef FUZZER_DEBUG
386
                        printf("get_sample_rate\n");
387
#endif
388
627
                        const bool res = decoder.get_sample_rate();
389
627
                        fuzzing::memory::memory_test(res);
390
627
                    }
391
627
                    break;
392
298
                case    12:
393
298
                    {
394
#ifdef FUZZER_DEBUG
395
                        printf("get_blocksize\n");
396
#endif
397
298
                        const bool res = decoder.get_blocksize();
398
298
                        fuzzing::memory::memory_test(res);
399
298
                    }
400
298
                    break;
401
286k
            }
402
286k
        }
403
8.95k
    } catch ( ... ) { }
404
405
8.95k
end:
406
8.95k
    {
407
8.95k
        const bool res = decoder.finish();
408
8.95k
        fuzzing::memory::memory_test(res);
409
8.95k
    }
410
8.95k
    return 0;
411
8.95k
}