diff options
Diffstat (limited to 'oss-fuzz/fuzz-decoder.cc')
-rw-r--r-- | oss-fuzz/fuzz-decoder.cc | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/oss-fuzz/fuzz-decoder.cc b/oss-fuzz/fuzz-decoder.cc new file mode 100644 index 00000000..b2733874 --- /dev/null +++ b/oss-fuzz/fuzz-decoder.cc @@ -0,0 +1,355 @@ +#include <cstddef> +#include <cstdint> + +#include <fuzzing/datasource/datasource.hpp> +#include <fuzzing/memory.hpp> + +#include "FLAC++/decoder.h" + +template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) { + (void)id; + switch ( Get<uint8_t>() ) { + case 0: + return FLAC__METADATA_TYPE_STREAMINFO; + case 1: + return FLAC__METADATA_TYPE_PADDING; + case 2: + return FLAC__METADATA_TYPE_APPLICATION; + case 3: + return FLAC__METADATA_TYPE_SEEKTABLE; + case 4: + return FLAC__METADATA_TYPE_VORBIS_COMMENT; + case 5: + return FLAC__METADATA_TYPE_CUESHEET; + case 6: + return FLAC__METADATA_TYPE_PICTURE; + case 7: + return FLAC__METADATA_TYPE_UNDEFINED; + case 8: + return FLAC__MAX_METADATA_TYPE; + default: + return FLAC__METADATA_TYPE_STREAMINFO; + } +} + +namespace FLAC { + namespace Decoder { + class FuzzerStream : public Stream { + private: + fuzzing::datasource::Datasource& ds; + public: + FuzzerStream(fuzzing::datasource::Datasource& dsrc) : + Stream(), ds(dsrc) { } + + ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override { + try { + const size_t maxCopySize = *bytes; + + if ( maxCopySize > 0 ) { + /* memset just to test if this overwrites anything, and triggers ASAN */ + memset(buffer, 0, maxCopySize); + } + + const auto data = ds.GetData(0); + const auto dataSize = data.size(); + const auto copySize = std::min(maxCopySize, dataSize); + + if ( copySize > 0 ) { + memcpy(buffer, data.data(), copySize); + } + + *bytes = copySize; + + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } catch ( ... ) { + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + } + + ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override { + { + fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header)); + fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer)); + } + + { + const auto numChannels = get_channels(); + const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32); + for (size_t i = 0; i < numChannels; i++) { + fuzzing::memory::memory_test(buffer[i], bytesPerChannel); + } + } + + try { + if ( ds.Get<bool>() == true ) { + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + } catch ( ... ) { } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + + void error_callback(::FLAC__StreamDecoderErrorStatus status) override { + fuzzing::memory::memory_test(status); + } + + void metadata_callback(const ::FLAC__StreamMetadata *metadata) override { + fuzzing::memory::memory_test(metadata->type); + fuzzing::memory::memory_test(metadata->is_last); + fuzzing::memory::memory_test(metadata->length); + fuzzing::memory::memory_test(metadata->data); + } + + ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override { + fuzzing::memory::memory_test(absolute_byte_offset); + + try { + if ( ds.Get<bool>() == true ) { + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + } else { + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + } + } catch ( ... ) { + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; + } + } +#if 0 + ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override { + fuzzing::memory::memory_test(*absolute_byte_offset); + + try { + if ( ds.Get<bool>() == true ) { + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } else { + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + } + } catch ( ... ) { + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } + } + + ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override { + fuzzing::memory::memory_test(*stream_length); + + try { + if ( ds.Get<bool>() == true ) { + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } else { + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; + } + } catch ( ... ) { + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; + } + } +#endif + }; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + fuzzing::datasource::Datasource ds(data, size); + FLAC::Decoder::FuzzerStream decoder(ds); + + try { + { + ::FLAC__StreamDecoderInitStatus ret; + + if ( ds.Get<bool>() ) { + ret = decoder.init(); + } else { + ret = decoder.init_ogg(); + } + + if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) { + goto end; + } + } + + if ( ds.Get<bool>() ) { +#ifdef FUZZER_DEBUG + printf("set_ogg_serial_number\n"); +#endif + decoder.set_ogg_serial_number(ds.Get<long>()); + } + if ( ds.Get<bool>() ) { +#ifdef FUZZER_DEBUG + printf("set_md5_checking\n"); +#endif + decoder.set_md5_checking(ds.Get<bool>()); + } + if ( ds.Get<bool>() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_respond\n"); +#endif + decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>()); + } + if ( ds.Get<bool>() ) { + const auto idVector = ds.GetData(0); + unsigned char id[4]; + if ( idVector.size() >= sizeof(id) ) { + memcpy(id, idVector.data(), sizeof(id)); +#ifdef FUZZER_DEBUG + printf("set_metadata_respond_application\n"); +#endif + decoder.set_metadata_respond_application(id); + } + } + if ( ds.Get<bool>() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_respond_all\n"); +#endif + decoder.set_metadata_respond_all(); + } + if ( ds.Get<bool>() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_ignore\n"); +#endif + decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>()); + } + if ( ds.Get<bool>() ) { + const auto idVector = ds.GetData(0); + unsigned char id[4]; + if ( idVector.size() >= sizeof(id) ) { + memcpy(id, idVector.data(), sizeof(id)); +#ifdef FUZZER_DEBUG + printf("set_metadata_ignore_application\n"); +#endif + decoder.set_metadata_ignore_application(id); + } + } + if ( ds.Get<bool>() ) { +#ifdef FUZZER_DEBUG + printf("set_metadata_ignore_all\n"); +#endif + decoder.set_metadata_ignore_all(); + } + + while ( ds.Get<bool>() ) { + switch ( ds.Get<uint8_t>() ) { + case 0: + { +#ifdef FUZZER_DEBUG + printf("flush\n"); +#endif + const bool res = decoder.flush(); + fuzzing::memory::memory_test(res); + } + break; + case 1: + { +#ifdef FUZZER_DEBUG + printf("reset\n"); +#endif + const bool res = decoder.reset(); + fuzzing::memory::memory_test(res); + } + break; + case 2: + { +#ifdef FUZZER_DEBUG + printf("process_single\n"); +#endif + const bool res = decoder.process_single(); + fuzzing::memory::memory_test(res); + } + break; + case 3: + { +#ifdef FUZZER_DEBUG + printf("process_until_end_of_metadata\n"); +#endif + const bool res = decoder.process_until_end_of_metadata(); + fuzzing::memory::memory_test(res); + } + break; + case 4: + { +#ifdef FUZZER_DEBUG + printf("process_until_end_of_stream\n"); +#endif + const bool res = decoder.process_until_end_of_stream(); + fuzzing::memory::memory_test(res); + } + break; + case 5: + { +#ifdef FUZZER_DEBUG + printf("skip_single_frame\n"); +#endif + const bool res = decoder.skip_single_frame(); + fuzzing::memory::memory_test(res); + } + break; + case 6: + { +#ifdef FUZZER_DEBUG + printf("seek_absolute\n"); +#endif + const bool res = decoder.seek_absolute(ds.Get<uint64_t>()); + fuzzing::memory::memory_test(res); + } + break; + case 7: + { +#ifdef FUZZER_DEBUG + printf("get_md5_checking\n"); +#endif + const bool res = decoder.get_md5_checking(); + fuzzing::memory::memory_test(res); + } + break; + case 8: + { +#ifdef FUZZER_DEBUG + printf("get_total_samples\n"); +#endif + const bool res = decoder.get_total_samples(); + fuzzing::memory::memory_test(res); + } + break; + case 9: + { +#ifdef FUZZER_DEBUG + printf("get_channels\n"); +#endif + const bool res = decoder.get_channels(); + fuzzing::memory::memory_test(res); + } + break; + case 10: + { +#ifdef FUZZER_DEBUG + printf("get_bits_per_sample\n"); +#endif + const bool res = decoder.get_bits_per_sample(); + fuzzing::memory::memory_test(res); + } + break; + case 11: + { +#ifdef FUZZER_DEBUG + printf("get_sample_rate\n"); +#endif + const bool res = decoder.get_sample_rate(); + fuzzing::memory::memory_test(res); + } + break; + case 12: + { +#ifdef FUZZER_DEBUG + printf("get_blocksize\n"); +#endif + const bool res = decoder.get_blocksize(); + fuzzing::memory::memory_test(res); + } + break; + } + } + } catch ( ... ) { } + +end: + { + const bool res = decoder.finish(); + fuzzing::memory::memory_test(res); + } + return 0; +} |