初始化内容
This commit is contained in:
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
# FLAC - Free Lossless Audio Codec
|
||||
# Copyright (C) 2019-2023 Xiph.Org Foundation
|
||||
#
|
||||
# This file is part the FLAC project. FLAC is comprised of several
|
||||
# components distributed under different licenses. The codec libraries
|
||||
# are distributed under Xiph.Org's BSD-like license (see the file
|
||||
# COPYING.Xiph in this distribution). All other programs, libraries, and
|
||||
# plugins are distributed under the GPL (see COPYING.GPL). The documentation
|
||||
# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
|
||||
# FLAC distribution contains at the top the terms under which it may be
|
||||
# distributed.
|
||||
#
|
||||
# Since this particular file is relevant to all components of FLAC,
|
||||
# it may be distributed under the Xiph.Org license, which is the least
|
||||
# restrictive of those mentioned above. See the file COPYING.Xiph in this
|
||||
# distribution.
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/oss-fuzz
|
||||
|
||||
AM_CFLAGS = ${LIB_FUZZING_ENGINE}
|
||||
AM_CXXFLAGS = -std=c++11 $(LIB_FUZZING_ENGINE)
|
||||
LDADD = $(flac_libs)
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
fuzzer_encoder.dict \
|
||||
common.h \
|
||||
Readme.md \
|
||||
fuzzing/datasource/datasource.hpp \
|
||||
fuzzing/datasource/id.hpp \
|
||||
fuzzing/exception.hpp \
|
||||
fuzzing/memory.hpp \
|
||||
fuzzing/types.hpp
|
||||
|
||||
noinst_PROGRAMS =
|
||||
|
||||
if USE_OSSFUZZERS
|
||||
noinst_PROGRAMS += fuzzer_encoder fuzzer_encoder_v2 fuzzer_decoder fuzzer_seek fuzzer_metadata fuzzer_reencoder fuzzer_tool_flac fuzzer_tool_metaflac
|
||||
endif
|
||||
|
||||
fuzzer_encoder_SOURCES = encoder.cc
|
||||
fuzzer_encoder_v2_SOURCES = encoder_v2.cc
|
||||
fuzzer_decoder_SOURCES = decoder.cc
|
||||
fuzzer_seek_SOURCES = seek.cc
|
||||
fuzzer_metadata_SOURCES = metadata.cc
|
||||
fuzzer_reencoder_SOURCES = reencoder.cc
|
||||
fuzzer_tool_flac_SOURCES = ${flac_SOURCES} empty.cc tool_flac.c # empty.cc is to force use of C++ linker, which is mandated by oss-fuzz
|
||||
fuzzer_tool_flac_LDADD = \
|
||||
$(top_builddir)/src/share/utf8/libutf8.la \
|
||||
$(top_builddir)/src/share/grabbag/libgrabbag.la \
|
||||
$(top_builddir)/src/share/getopt/libgetopt.la \
|
||||
$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
|
||||
$(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
|
||||
$(top_builddir)/src/libFLAC/libFLAC.la \
|
||||
@LTLIBICONV@ \
|
||||
-lm
|
||||
fuzzer_tool_metaflac_SOURCES = ${metaflac_SOURCES} empty.cc tool_metaflac.c # empty.cc is to force use of C++ linker, which is mandated by oss-fuzz
|
||||
fuzzer_tool_metaflac_LDADD = \
|
||||
$(top_builddir)/src/share/utf8/libutf8.la \
|
||||
$(top_builddir)/src/share/grabbag/libgrabbag.la \
|
||||
$(top_builddir)/src/share/getopt/libgetopt.la \
|
||||
$(top_builddir)/src/share/replaygain_analysis/libreplaygain_analysis.la \
|
||||
$(top_builddir)/src/share/replaygain_synthesis/libreplaygain_synthesis.la \
|
||||
$(top_builddir)/src/libFLAC/libFLAC.la \
|
||||
@LTLIBICONV@ \
|
||||
-lm
|
||||
|
||||
flac_libs = \
|
||||
$(top_builddir)/src/libFLAC/libFLAC-static.la \
|
||||
$(top_builddir)/src/libFLAC++/libFLAC++-static.la \
|
||||
@OGG_LIBS@ \
|
||||
-lm
|
||||
|
||||
flac_SOURCES = \
|
||||
${top_builddir}/src/flac/analyze.c \
|
||||
${top_builddir}/src/flac/decode.c \
|
||||
${top_builddir}/src/flac/encode.c \
|
||||
${top_builddir}/src/flac/foreign_metadata.c \
|
||||
${top_builddir}/src/flac/local_string_utils.c \
|
||||
${top_builddir}/src/flac/utils.c \
|
||||
${top_builddir}/src/flac/vorbiscomment.c \
|
||||
${top_builddir}/src/flac/analyze.h \
|
||||
${top_builddir}/src/flac/decode.h \
|
||||
${top_builddir}/src/flac/encode.h \
|
||||
${top_builddir}/src/flac/foreign_metadata.h \
|
||||
${top_builddir}/src/flac/local_string_utils.h \
|
||||
${top_builddir}/src/flac/utils.h \
|
||||
${top_builddir}/src/flac/vorbiscomment.h
|
||||
|
||||
metaflac_SOURCES = \
|
||||
${top_builddir}/src/metaflac/operations.c \
|
||||
${top_builddir}/src/metaflac/operations_shorthand_cuesheet.c \
|
||||
${top_builddir}/src/metaflac/operations_shorthand_picture.c \
|
||||
${top_builddir}/src/metaflac/operations_shorthand_seektable.c \
|
||||
${top_builddir}/src/metaflac/operations_shorthand_streaminfo.c \
|
||||
${top_builddir}/src/metaflac/operations_shorthand_vorbiscomment.c \
|
||||
${top_builddir}/src/metaflac/options.c \
|
||||
${top_builddir}/src/metaflac/usage.c \
|
||||
${top_builddir}/src/metaflac/utils.c \
|
||||
${top_builddir}/src/metaflac/operations.h \
|
||||
${top_builddir}/src/metaflac/operations_shorthand.h \
|
||||
${top_builddir}/src/metaflac/options.h \
|
||||
${top_builddir}/src/metaflac/usage.h \
|
||||
${top_builddir}/src/metaflac/utils.h
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
Fuzzers fuzzer_decoder.cc and fuzzer_encoder.cc were taken from
|
||||
|
||||
https://github.com/guidovranken/flac-fuzzers
|
||||
|
||||
The header files in the directory fuzzing and below were taken from:
|
||||
|
||||
https://github.com/guidovranken/fuzzing-headers.git
|
||||
|
||||
Some minor modifications were made to make them build with the default C++
|
||||
warning flags.
|
||||
|
||||
The code mentioned above, contributed by Guido Vranken, is licensed under
|
||||
the MIT license. See the files themselves for details
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
extern int alloc_check_threshold, alloc_check_counter;
|
||||
int alloc_check_threshold = INT32_MAX, alloc_check_counter = 0;
|
||||
Vendored
+408
@@ -0,0 +1,408 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <fuzzing/datasource/datasource.hpp>
|
||||
#include <fuzzing/memory.hpp>
|
||||
|
||||
#include "FLAC++/decoder.h"
|
||||
#include "FLAC++/metadata.h"
|
||||
#include "common.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 {
|
||||
Metadata::Prototype * cloned_object = nullptr;
|
||||
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);
|
||||
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
cloned_object = new Metadata::StreamInfo(metadata);
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_PADDING)
|
||||
cloned_object = new Metadata::Padding(metadata);
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION)
|
||||
cloned_object = new Metadata::Application(metadata);
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_SEEKTABLE)
|
||||
cloned_object = new Metadata::SeekTable(metadata);
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
cloned_object = new Metadata::VorbisComment(metadata);
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_CUESHEET)
|
||||
cloned_object = new Metadata::CueSheet(metadata);
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_PICTURE)
|
||||
cloned_object = new Metadata::Picture(metadata);
|
||||
else
|
||||
return;
|
||||
if (0 != cloned_object && *cloned_object == *metadata && cloned_object->is_valid()) {
|
||||
if (cloned_object->get_type() == FLAC__METADATA_TYPE_SEEKTABLE)
|
||||
dynamic_cast<Metadata::SeekTable *>(cloned_object)->is_legal();
|
||||
if (cloned_object->get_type() == FLAC__METADATA_TYPE_PICTURE)
|
||||
dynamic_cast<Metadata::Picture *>(cloned_object)->is_legal(NULL);
|
||||
if (cloned_object->get_type() == FLAC__METADATA_TYPE_CUESHEET)
|
||||
dynamic_cast<Metadata::CueSheet *>(cloned_object)->is_legal(true,NULL);
|
||||
}
|
||||
delete cloned_object;
|
||||
}
|
||||
|
||||
::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);
|
||||
bool use_ogg = true;
|
||||
|
||||
try {
|
||||
if ( ds.Get<bool>() ) {
|
||||
use_ogg = false;
|
||||
}
|
||||
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();
|
||||
}
|
||||
{
|
||||
::FLAC__StreamDecoderInitStatus ret;
|
||||
if ( !use_ogg ) {
|
||||
ret = decoder.init();
|
||||
} else {
|
||||
ret = decoder.init_ogg();
|
||||
}
|
||||
|
||||
if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Vendored
Vendored
+257
@@ -0,0 +1,257 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include <fuzzing/datasource/datasource.hpp>
|
||||
#include <fuzzing/memory.hpp>
|
||||
|
||||
#include "FLAC++/encoder.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace FLAC {
|
||||
namespace Encoder {
|
||||
class FuzzerStream : public Stream {
|
||||
private:
|
||||
// fuzzing::datasource::Datasource& ds;
|
||||
public:
|
||||
FuzzerStream(fuzzing::datasource::Datasource&) :
|
||||
Stream() { }
|
||||
|
||||
::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override {
|
||||
fuzzing::memory::memory_test(buffer, bytes);
|
||||
#if 0
|
||||
try {
|
||||
if ( ds.Get<bool>() == true ) {
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
|
||||
}
|
||||
} catch ( ... ) { }
|
||||
#endif
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
fuzzing::datasource::Datasource ds(data, size);
|
||||
FLAC::Encoder::FuzzerStream encoder(ds);
|
||||
|
||||
try {
|
||||
const int channels = ds.Get<uint8_t>();
|
||||
const int bps = ds.Get<uint8_t>();
|
||||
encoder.set_channels(channels);
|
||||
encoder.set_bits_per_sample(bps);
|
||||
|
||||
{
|
||||
const bool res = encoder.set_streamable_subset(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_ogg_serial_number(ds.Get<long>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_verify(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_compression_level(ds.Get<uint8_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_do_exhaustive_model_search(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const auto s = ds.Get<std::string>();
|
||||
const bool res = encoder.set_apodization(s.data());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_do_qlp_coeff_prec_search(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_do_escape_coding(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_rice_parameter_search_dist(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_blocksize(ds.Get<uint16_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_sample_rate(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
|
||||
if ( size > 2 * 65535 * 4 ) {
|
||||
/* With large inputs and expensive options enabled, the fuzzer can get *really* slow.
|
||||
* Some combinations can make the fuzzer timeout (>60 seconds). However, while combining
|
||||
* options makes the fuzzer slower, most options do not expose new code when combined.
|
||||
* Therefore, combining slow options is disabled for large inputs. Any input containing
|
||||
* more than 65536 * 2 samples of 32 bits each (max blocksize, stereo) is considered large
|
||||
*/
|
||||
encoder.set_do_qlp_coeff_prec_search(false);
|
||||
encoder.set_do_exhaustive_model_search(false);
|
||||
}
|
||||
if ( size > 2 * 4096 * 4 + 250 ) {
|
||||
/* With subdivide_tukey in the mix testing apodizations can get really expensive. Therefore
|
||||
* this is disabled for inputs of more than one whole stereo block of 32-bit inputs plus a
|
||||
* bit of overhead */
|
||||
encoder.set_apodization("");
|
||||
}
|
||||
|
||||
{
|
||||
::FLAC__StreamEncoderInitStatus ret;
|
||||
if ( ds.Get<bool>() ) {
|
||||
ret = encoder.init();
|
||||
} else {
|
||||
ret = encoder.init_ogg();
|
||||
}
|
||||
|
||||
if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* These sets must fail, because encoder is already initialized */
|
||||
{
|
||||
bool res = false;
|
||||
res = res || encoder.set_streamable_subset(true);
|
||||
res = res || encoder.set_ogg_serial_number(0);
|
||||
res = res || encoder.set_verify(true);
|
||||
res = res || encoder.set_compression_level(0);
|
||||
res = res || encoder.set_do_exhaustive_model_search(true);
|
||||
res = res || encoder.set_do_mid_side_stereo(true);
|
||||
res = res || encoder.set_loose_mid_side_stereo(true);
|
||||
res = res || encoder.set_apodization("test");
|
||||
res = res || encoder.set_max_lpc_order(0);
|
||||
res = res || encoder.set_qlp_coeff_precision(0);
|
||||
res = res || encoder.set_do_qlp_coeff_prec_search(true);
|
||||
res = res || encoder.set_do_escape_coding(true);
|
||||
res = res || encoder.set_min_residual_partition_order(0);
|
||||
res = res || encoder.set_max_residual_partition_order(0);
|
||||
res = res || encoder.set_rice_parameter_search_dist(0);
|
||||
res = res || encoder.set_total_samples_estimate(0);
|
||||
res = res || encoder.set_channels(channels);
|
||||
res = res || encoder.set_bits_per_sample(16);
|
||||
res = res || encoder.set_limit_min_bitrate(true);
|
||||
res = res || encoder.set_blocksize(3021);
|
||||
res = res || encoder.set_sample_rate(44100);
|
||||
fuzzing::memory::memory_test(res);
|
||||
if(res)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/* XORing values as otherwise compiler will optimize, apparently */
|
||||
bool res = false;
|
||||
res = res != encoder.get_streamable_subset();
|
||||
res = res != encoder.get_verify();
|
||||
res = res != encoder.get_do_exhaustive_model_search();
|
||||
res = res != encoder.get_do_mid_side_stereo();
|
||||
res = res != encoder.get_loose_mid_side_stereo();
|
||||
res = res != encoder.get_max_lpc_order();
|
||||
res = res != encoder.get_qlp_coeff_precision();
|
||||
res = res != encoder.get_do_qlp_coeff_prec_search();
|
||||
res = res != encoder.get_do_escape_coding();
|
||||
res = res != encoder.get_min_residual_partition_order();
|
||||
res = res != encoder.get_max_residual_partition_order();
|
||||
res = res != encoder.get_rice_parameter_search_dist();
|
||||
res = res != encoder.get_total_samples_estimate();
|
||||
res = res != encoder.get_channels();
|
||||
res = res != encoder.get_bits_per_sample();
|
||||
res = res != encoder.get_limit_min_bitrate();
|
||||
res = res != encoder.get_blocksize();
|
||||
res = res != encoder.get_sample_rate();
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
|
||||
|
||||
while ( ds.Get<bool>() ) {
|
||||
{
|
||||
auto dat = ds.GetVector<FLAC__int32>();
|
||||
|
||||
if( ds.Get<bool>() )
|
||||
/* Mask */
|
||||
for (size_t i = 0; i < dat.size(); i++)
|
||||
/* If we get here, bps is 4 or larger, or init will have failed */
|
||||
dat[i] = (int32_t)(((uint32_t)(dat[i]) << (32-bps)) >> (32-bps));
|
||||
|
||||
const uint32_t samples = dat.size() / channels;
|
||||
if ( samples > 0 ) {
|
||||
const int32_t* ptr = dat.data();
|
||||
const bool res = encoder.process_interleaved(ptr, samples);
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( ... ) { }
|
||||
|
||||
end:
|
||||
{
|
||||
const bool res = encoder.finish();
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Vendored
+352
@@ -0,0 +1,352 @@
|
||||
/* fuzzer_encoder_v2
|
||||
* Copyright (C) 2022-2023 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the Xiph.org Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring> /* for memcpy */
|
||||
#include "FLAC/stream_encoder.h"
|
||||
#include "FLAC/metadata.h"
|
||||
extern "C" {
|
||||
#include "share/private.h"
|
||||
}
|
||||
#include "common.h"
|
||||
|
||||
/* This C++ fuzzer uses the FLAC and not FLAC++ because the latter lacks a few
|
||||
* hidden functions like FLAC__stream_encoder_disable_constant_subframes. It
|
||||
* is still processed by a C++ compiler because that's what oss-fuzz expects */
|
||||
|
||||
|
||||
static FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
|
||||
{
|
||||
(void)encoder, (void)buffer, (void)bytes, (void)samples, (void)current_frame, (void)client_data;
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
FLAC__bool encoder_valid = true;
|
||||
FLAC__StreamEncoder *encoder = 0;
|
||||
FLAC__StreamEncoderState state;
|
||||
FLAC__StreamMetadata *metadata[16] = {NULL};
|
||||
unsigned num_metadata = 0;
|
||||
FLAC__StreamMetadata_VorbisComment_Entry VorbisCommentField;
|
||||
|
||||
unsigned sample_rate, channels, bps;
|
||||
uint64_t samples_estimate, samples_in_input;
|
||||
unsigned compression_level, input_data_width, blocksize, max_lpc_order, qlp_coeff_precision, min_residual_partition_order, max_residual_partition_order, metadata_mask, instruction_set_disable_mask;
|
||||
FLAC__bool ogg, write_to_file, interleaved;
|
||||
|
||||
FLAC__bool data_bools[24];
|
||||
|
||||
/* Set alloc threshold. This check was added later and no spare config
|
||||
* bytes were left, so we're reusing the sample rate as that of little
|
||||
* consequence to the encoder and decoder except reading the frame header */
|
||||
|
||||
if(size < 3)
|
||||
return 0;
|
||||
alloc_check_threshold = data[2];
|
||||
alloc_check_counter = 0;
|
||||
|
||||
/* allocate the encoder */
|
||||
if((encoder = FLAC__stream_encoder_new()) == NULL) {
|
||||
fprintf(stderr, "ERROR: allocating encoder\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Use first 20 byte for configuration */
|
||||
if(size < 20){
|
||||
FLAC__stream_encoder_delete(encoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First 3 byte for sample rate, 4th byte for channels, 5th byte for bps */
|
||||
sample_rate = ((unsigned)data[0] << 16) + ((unsigned)data[1] << 8) + data[2];
|
||||
channels = data[3];
|
||||
bps = data[4];
|
||||
|
||||
/* Number of samples estimate, format accepts 36-bit max */
|
||||
samples_estimate = ((uint64_t)data[5] << 32) + ((unsigned)data[6] << 24) + ((unsigned)data[7] << 16) + ((unsigned)data[8] << 8) + data[9];
|
||||
|
||||
compression_level = data[10]&0b1111;
|
||||
input_data_width = 1 + (data[10]>>4)%4;
|
||||
samples_in_input = (size-20)/input_data_width;
|
||||
blocksize = ((unsigned)data[11] << 8) + (unsigned)data[12];
|
||||
max_lpc_order = data[13];
|
||||
qlp_coeff_precision = data[14];
|
||||
min_residual_partition_order = data[15] & 0b1111;
|
||||
max_residual_partition_order = data[15] & 0b11110000;
|
||||
metadata_mask = data[16];
|
||||
instruction_set_disable_mask = data[17];
|
||||
|
||||
/* Get array of bools from configuration */
|
||||
for(int i = 0; i < 16; i++)
|
||||
data_bools[i] = data[18+i/8] & (1 << (i % 8));
|
||||
|
||||
ogg = data_bools[0];
|
||||
interleaved = data_bools[1];
|
||||
write_to_file = data_bools[13];
|
||||
|
||||
/* Set input and process parameters */
|
||||
encoder_valid &= FLAC__stream_encoder_set_verify(encoder, data_bools[2]);
|
||||
encoder_valid &= FLAC__stream_encoder_set_channels(encoder, channels);
|
||||
encoder_valid &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
|
||||
encoder_valid &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
|
||||
encoder_valid &= FLAC__stream_encoder_set_total_samples_estimate(encoder, samples_estimate);
|
||||
encoder_valid &= FLAC__stream_encoder_disable_instruction_set(encoder, instruction_set_disable_mask);
|
||||
encoder_valid &= FLAC__stream_encoder_set_limit_min_bitrate(encoder, data_bools[15]);
|
||||
|
||||
/* Set compression related parameters */
|
||||
encoder_valid &= FLAC__stream_encoder_set_compression_level(encoder, compression_level);
|
||||
if(data_bools[3]){
|
||||
/* Bias towards regular compression levels */
|
||||
encoder_valid &= FLAC__stream_encoder_set_blocksize(encoder, blocksize);
|
||||
encoder_valid &= FLAC__stream_encoder_set_max_lpc_order(encoder, max_lpc_order);
|
||||
encoder_valid &= FLAC__stream_encoder_set_qlp_coeff_precision(encoder, qlp_coeff_precision);
|
||||
encoder_valid &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, min_residual_partition_order);
|
||||
|
||||
/* With large inputs and expensive options enabled, the fuzzer can get *really* slow.
|
||||
* Some combinations can make the fuzzer timeout (>60 seconds). However, while combining
|
||||
* options makes the fuzzer slower, most options do not expose new code when combined.
|
||||
* Therefore, combining slow options is disabled for large inputs. Any input containing
|
||||
* more than 65536 * 2 samples (max blocksize, stereo) is considered large
|
||||
*/
|
||||
if(samples_in_input < (2*65536)) {
|
||||
encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, data_bools[4]);
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, data_bools[5]);
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, data_bools[6]);
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, data_bools[7]);
|
||||
/* Combining model search, precision search and a high residual partition order is especially
|
||||
* expensive, so limit that even further. This high partition order can only be set on
|
||||
* large blocksize and with streamable subset disabled */
|
||||
if(samples_in_input < (2 * 4609) || data_bools[4] || !data_bools[7] || !data_bools[5] || max_residual_partition_order < 9 || blocksize < 4609)
|
||||
encoder_valid &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, max_residual_partition_order);
|
||||
}
|
||||
else {
|
||||
if(!data_bools[4])
|
||||
encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, false);
|
||||
else if(data_bools[6])
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, true);
|
||||
else if(data_bools[7])
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, true);
|
||||
else if(data_bools[5])
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, true);
|
||||
}
|
||||
encoder_valid &= FLAC__stream_encoder_set_do_mid_side_stereo(encoder, data_bools[8]);
|
||||
encoder_valid &= FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, data_bools[9]);
|
||||
|
||||
encoder_valid &= FLAC__stream_encoder_disable_constant_subframes(encoder, data_bools[10]);
|
||||
encoder_valid &= FLAC__stream_encoder_disable_fixed_subframes(encoder, data_bools[11]);
|
||||
encoder_valid &= FLAC__stream_encoder_disable_verbatim_subframes(encoder, data_bools[12]);
|
||||
}
|
||||
|
||||
/* Disable alloc check if requested */
|
||||
if(encoder_valid && data_bools[14])
|
||||
alloc_check_threshold = INT32_MAX;
|
||||
|
||||
/* add metadata */
|
||||
if(encoder_valid && (metadata_mask & 1)) {
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO)) == NULL)
|
||||
encoder_valid = false;
|
||||
else
|
||||
num_metadata++;
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 2) && size > 21){
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL)
|
||||
encoder_valid = false;
|
||||
else {
|
||||
metadata[num_metadata++]->length = (((unsigned)data[20]) << 8) + (unsigned)(data[21]);
|
||||
}
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 4) && size > 20){
|
||||
FLAC__byte * application_data = (FLAC__byte *)malloc(size-20);
|
||||
if(0 != application_data && ((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)) == NULL))
|
||||
encoder_valid = false;
|
||||
else {
|
||||
memcpy(application_data,data+20,size-20);
|
||||
FLAC__metadata_object_application_set_data(metadata[num_metadata++], application_data, size-20, 0);
|
||||
}
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 8) && size > 25){
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE)) == NULL)
|
||||
encoder_valid = false;
|
||||
else {
|
||||
unsigned seekpoint_spacing = ((unsigned)data[22] << 8) + data[23];
|
||||
unsigned total_samples_for_seekpoints = ((unsigned)data[24] << 8) + data[25];
|
||||
FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(metadata[num_metadata++], seekpoint_spacing, total_samples_for_seekpoints);
|
||||
}
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 16)){
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) != NULL) {
|
||||
bool vorbiscomment_valid = true;
|
||||
/* Append a vorbis comment */
|
||||
if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Nothing to 🤔 report"))
|
||||
vorbiscomment_valid = false;
|
||||
else {
|
||||
if(FLAC__metadata_object_vorbiscomment_append_comment(metadata[num_metadata], VorbisCommentField, false)) {
|
||||
|
||||
/* Insert a vorbis comment at the first index */
|
||||
if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Still nothing to report 🤔🤣"))
|
||||
vorbiscomment_valid = false;
|
||||
else
|
||||
if(!FLAC__metadata_object_vorbiscomment_insert_comment(metadata[num_metadata], 0, VorbisCommentField, false)) {
|
||||
free(VorbisCommentField.entry);
|
||||
vorbiscomment_valid = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(VorbisCommentField.entry);
|
||||
vorbiscomment_valid = false;
|
||||
}
|
||||
}
|
||||
if(!vorbiscomment_valid) {
|
||||
FLAC__metadata_object_delete(metadata[num_metadata]);
|
||||
metadata[num_metadata] = 0;
|
||||
}
|
||||
else
|
||||
num_metadata++;
|
||||
}
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 32)){
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)) != NULL) {
|
||||
if(!FLAC__metadata_object_cuesheet_insert_blank_track(metadata[num_metadata],0)) {
|
||||
FLAC__metadata_object_delete(metadata[num_metadata]);
|
||||
metadata[num_metadata] = 0;
|
||||
}
|
||||
else {
|
||||
if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(metadata[num_metadata],0,0)) {
|
||||
FLAC__metadata_object_delete(metadata[num_metadata]);
|
||||
metadata[num_metadata] = 0;
|
||||
}
|
||||
else {
|
||||
metadata[num_metadata]->data.cue_sheet.tracks[0].number = 1;
|
||||
num_metadata++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 64)){
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) != NULL) {
|
||||
num_metadata++;
|
||||
}
|
||||
}
|
||||
if(encoder_valid && (metadata_mask & 128)){
|
||||
if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_UNDEFINED)) != NULL) {
|
||||
metadata[num_metadata]->length = 24;
|
||||
metadata[num_metadata]->data.unknown.data = (FLAC__byte *)calloc(24, 1);
|
||||
num_metadata++;
|
||||
}
|
||||
}
|
||||
|
||||
if(num_metadata && encoder_valid)
|
||||
encoder_valid = FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata);
|
||||
|
||||
/* initialize encoder */
|
||||
if(encoder_valid) {
|
||||
FLAC__StreamEncoderInitStatus init_status;
|
||||
if(ogg)
|
||||
if(write_to_file)
|
||||
init_status = FLAC__stream_encoder_init_ogg_file(encoder, "/tmp/tmp.flac", NULL, NULL);
|
||||
else
|
||||
init_status = FLAC__stream_encoder_init_ogg_stream(encoder, NULL, write_callback, NULL, NULL, NULL, NULL);
|
||||
else
|
||||
if(write_to_file)
|
||||
init_status = FLAC__stream_encoder_init_file(encoder, "/tmp/tmp.flac", NULL, NULL);
|
||||
else
|
||||
init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, NULL);
|
||||
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
|
||||
encoder_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* send samples to encoder */
|
||||
if(encoder_valid && size > (input_data_width*channels+26)) {
|
||||
unsigned samples = (size - 26)/input_data_width/channels;
|
||||
const uint8_t * pcm_data = data + 26;
|
||||
int32_t * data_as_int32 = (int32_t *)malloc(4*samples*channels);
|
||||
if(0 != data_as_int32){
|
||||
for(unsigned i = 0; i < samples*channels; i++)
|
||||
if(input_data_width == 1)
|
||||
data_as_int32[i] = (int32_t)pcm_data[i] - 0x80;
|
||||
else if(input_data_width == 2)
|
||||
data_as_int32[i] = (((int32_t)pcm_data[i*2] << 8) + pcm_data[i*2+1]) - 0x8000;
|
||||
else if(input_data_width == 3)
|
||||
data_as_int32[i] = (((int32_t)pcm_data[i*3] << 16) + ((int32_t)pcm_data[i*3+1] << 8) + pcm_data[i*3+2]) - 0x800000;
|
||||
else if(input_data_width == 4)
|
||||
data_as_int32[i] = (((int64_t)pcm_data[i*4] << 24) + ((int32_t)pcm_data[i*4+1] << 16) + ((int32_t)pcm_data[i*4+2] << 8) + pcm_data[i*4+3]) - 0x80000000;
|
||||
|
||||
/* feed samples to encoder */
|
||||
if(interleaved)
|
||||
encoder_valid = FLAC__stream_encoder_process_interleaved(encoder, data_as_int32, samples);
|
||||
else {
|
||||
encoder_valid = FLAC__stream_encoder_process(encoder, (const int32_t*[]){data_as_int32,
|
||||
data_as_int32+samples,
|
||||
data_as_int32+samples*2,
|
||||
data_as_int32+samples*3,
|
||||
data_as_int32+samples*4, data_as_int32+samples*5, data_as_int32+samples*6, data_as_int32+samples*7}, samples);
|
||||
}
|
||||
free(data_as_int32);
|
||||
}
|
||||
else {
|
||||
encoder_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
state = FLAC__stream_encoder_get_state(encoder);
|
||||
if(!(state == FLAC__STREAM_ENCODER_OK ||
|
||||
state == FLAC__STREAM_ENCODER_UNINITIALIZED ||
|
||||
state == FLAC__STREAM_ENCODER_CLIENT_ERROR ||
|
||||
((state == FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR ||
|
||||
state == FLAC__STREAM_ENCODER_FRAMING_ERROR ||
|
||||
(state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR &&
|
||||
FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR)) &&
|
||||
alloc_check_threshold < INT32_MAX))) {
|
||||
fprintf(stderr,"-----\nERROR: stream encoder returned %s\n-----\n",FLAC__stream_encoder_get_resolved_state_string(encoder));
|
||||
if(state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) {
|
||||
uint32_t frame_number, channel, sample_number;
|
||||
FLAC__int32 expected, got;
|
||||
FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, NULL, &frame_number, &channel, &sample_number, &expected, &got);
|
||||
fprintf(stderr,"Frame number %d\nChannel %d\n Sample number %d\nExpected value %d\nGot %d\n", frame_number, channel, sample_number, expected, got);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
FLAC__stream_encoder_finish(encoder);
|
||||
|
||||
/* now that encoding is finished, the metadata can be freed */
|
||||
for(unsigned i = 0; i < 16; i++)
|
||||
if(0 != metadata[i])
|
||||
FLAC__metadata_object_delete(metadata[i]);
|
||||
|
||||
FLAC__stream_encoder_delete(encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
flac_stream_marker="fLaC"
|
||||
ogg_stream_marker="OggS"
|
||||
flac_in_ogg_marker="\x7fFLAC"
|
||||
|
||||
synccode_fixed_blocksize="\xFF\xF8"
|
||||
synccode_variable_blocksize="\xFF\xF9"
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
"bartlett"
|
||||
"bartlett_hann"
|
||||
"blackman"
|
||||
"blackman_harris_4term_92db"
|
||||
"connes"
|
||||
"flattop"
|
||||
"gauss()"
|
||||
"hamming"
|
||||
"hann"
|
||||
"kaiser_bessel"
|
||||
"nuttall"
|
||||
"rectangle"
|
||||
"triangle"
|
||||
"tukey(0)"
|
||||
"partial_tukey(0)"
|
||||
"punchout_tukey(0)"
|
||||
"subdivide_tukey(0)"
|
||||
"welch"
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
flac_stream_marker="fLaC"
|
||||
ogg_stream_marker="OggS"
|
||||
flac_in_ogg_marker="\x7fFLAC"
|
||||
|
||||
synccode_fixed_blocksize="\xFF\xF8"
|
||||
synccode_variable_blocksize="\xFF\xF9"
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
"--keep-foreign-metadata-if-present"
|
||||
"--replay-gain"
|
||||
"--apply-replaygain-which-is-not-lossless"
|
||||
|
||||
"--force-raw-format"
|
||||
"--force-aiff-format"
|
||||
"--force-rf64-format"
|
||||
"--force-wave64-format"
|
||||
"--force-aiff-c-sowt-format"
|
||||
"--force-aiff-c-none-format"
|
||||
"--force-legacy-wave-format"
|
||||
"--force-extensible-wave-format"
|
||||
|
||||
"--endian=big"
|
||||
"--sample-rate=1"
|
||||
"--channels=1"
|
||||
"--bps=32"
|
||||
"--sign=unsigned"
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fuzzing/exception.hpp>
|
||||
#include <fuzzing/types.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fuzzing {
|
||||
namespace datasource {
|
||||
|
||||
class Base
|
||||
{
|
||||
protected:
|
||||
virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
|
||||
public:
|
||||
Base(void) = default;
|
||||
virtual ~Base(void) = default;
|
||||
|
||||
template<class T> T Get(const uint64_t id = 0);
|
||||
uint16_t GetChoice(const uint64_t id = 0);
|
||||
std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
|
||||
template <class T> std::vector<T> GetVector(const uint64_t id = 0);
|
||||
|
||||
class OutOfData : public fuzzing::exception::FlowException {
|
||||
public:
|
||||
OutOfData() = default;
|
||||
};
|
||||
|
||||
class DeserializationFailure : public fuzzing::exception::FlowException {
|
||||
public:
|
||||
DeserializationFailure() = default;
|
||||
};
|
||||
};
|
||||
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
template<class T> T Base::Get(const uint64_t id)
|
||||
{
|
||||
T ret;
|
||||
const auto v = get(sizeof(ret), sizeof(ret), id);
|
||||
memcpy(&ret, v.data(), sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <> bool Base::Get<bool>(const uint64_t id)
|
||||
{
|
||||
uint8_t ret;
|
||||
const auto v = get(sizeof(ret), sizeof(ret), id);
|
||||
memcpy(&ret, v.data(), sizeof(ret));
|
||||
return (ret % 2) ? true : false;
|
||||
}
|
||||
|
||||
template <> std::string Base::Get<std::string>(const uint64_t id)
|
||||
{
|
||||
auto data = GetData(id);
|
||||
return std::string(data.data(), data.data() + data.size());
|
||||
}
|
||||
|
||||
template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
while ( true ) {
|
||||
auto data = GetData(id);
|
||||
ret.push_back( std::string(data.data(), data.data() + data.size()) );
|
||||
if ( Get<bool>(id) == false ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t Base::GetChoice(const uint64_t id)
|
||||
{
|
||||
return Get<uint16_t>(id);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
|
||||
{
|
||||
return get(min, max, id);
|
||||
}
|
||||
|
||||
|
||||
template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
|
||||
const auto data = GetData(id);
|
||||
types::String<> ret(data.data(), data.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
|
||||
const auto data = GetData(id);
|
||||
types::Data<> ret(data.data(), data.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::vector<T> Base::GetVector(const uint64_t id) {
|
||||
std::vector<T> ret;
|
||||
|
||||
while ( Get<bool>(id) == true ) {
|
||||
ret.push_back( Get<T>(id) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
class Datasource : public Base
|
||||
{
|
||||
private:
|
||||
const uint8_t* data;
|
||||
const size_t size;
|
||||
size_t idx;
|
||||
size_t left;
|
||||
std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;
|
||||
|
||||
// Make copy constructor and assignment operator private.
|
||||
Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
|
||||
Datasource& operator=(const Datasource &) { return *this; }
|
||||
public:
|
||||
Datasource(const uint8_t* _data, const size_t _size);
|
||||
};
|
||||
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
Datasource::Datasource(const uint8_t* _data, const size_t _size) :
|
||||
Base(), data(_data), size(_size), idx(0), left(size)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
|
||||
(void)id;
|
||||
|
||||
uint32_t getSize;
|
||||
if ( left < sizeof(getSize) ) {
|
||||
throw OutOfData();
|
||||
}
|
||||
memcpy(&getSize, data + idx, sizeof(getSize));
|
||||
idx += sizeof(getSize);
|
||||
left -= sizeof(getSize);
|
||||
|
||||
if ( getSize < min ) {
|
||||
getSize = min;
|
||||
}
|
||||
if ( max && getSize > max ) {
|
||||
getSize = max;
|
||||
}
|
||||
|
||||
if ( left < getSize ) {
|
||||
throw OutOfData();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ret(getSize);
|
||||
|
||||
if ( getSize > 0 ) {
|
||||
memcpy(ret.data(), data + idx, getSize);
|
||||
}
|
||||
idx += getSize;
|
||||
left -= getSize;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* namespace datasource */
|
||||
} /* namespace fuzzing */
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
namespace fuzzing {
|
||||
namespace datasource {
|
||||
|
||||
/* From: https://gist.github.com/underscorediscovery/81308642d0325fd386237cfa3b44785c */
|
||||
inline uint64_t hash_64_fnv1a(const void* key, const uint64_t len) {
|
||||
|
||||
const char* data = (char*)key;
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
uint64_t prime = 0x100000001b3;
|
||||
|
||||
for(uint64_t i = 0; i < len; ++i) {
|
||||
uint8_t value = data[i];
|
||||
hash = hash ^ value;
|
||||
hash *= prime;
|
||||
}
|
||||
|
||||
return hash;
|
||||
|
||||
} //hash_64_fnv1a
|
||||
|
||||
// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit
|
||||
// str should be a null terminated string literal, value should be left out
|
||||
// e.g hash_32_fnv1a_const("example")
|
||||
// code license: public domain or equivalent
|
||||
// post: https://notes.underscorediscovery.com/constexpr-fnv1a/
|
||||
|
||||
constexpr uint32_t val_32_const = 0x811c9dc5;
|
||||
constexpr uint32_t prime_32_const = 0x1000193;
|
||||
constexpr uint64_t val_64_const = 0xcbf29ce484222325;
|
||||
constexpr uint64_t prime_64_const = 0x100000001b3;
|
||||
|
||||
|
||||
inline constexpr uint64_t ID(const char* const str, const uint64_t value = val_64_const) noexcept {
|
||||
auto ret = (str[0] == '\0') ? value : ID(&str[1], (value ^ uint64_t(str[0])) * prime_64_const);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline constexpr std::pair<const char*, uint64_t> IDPair(const char* const str, const uint64_t value = val_64_const) noexcept {
|
||||
return {str, ID(str, value)};
|
||||
}
|
||||
|
||||
using IDMap = std::map<const char*, uint64_t>;
|
||||
|
||||
} /* namespace datasource */
|
||||
} /* namespace fuzzing */
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace fuzzing {
|
||||
namespace exception {
|
||||
|
||||
class ExceptionBase : public std::exception {
|
||||
public:
|
||||
ExceptionBase(void) = default;
|
||||
/* typeid(T).name */
|
||||
};
|
||||
|
||||
/* Recoverable exception */
|
||||
class FlowException : public ExceptionBase {
|
||||
public:
|
||||
FlowException(void) : ExceptionBase() { }
|
||||
};
|
||||
|
||||
/* Error in this library, should never happen */
|
||||
class LogicException : public ExceptionBase {
|
||||
private:
|
||||
std::string reason;
|
||||
public:
|
||||
LogicException(const std::string r) : ExceptionBase(), reason(r) { }
|
||||
virtual const char* what(void) const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
/* Error in target application */
|
||||
class TargetException : public ExceptionBase {
|
||||
private:
|
||||
std::string reason;
|
||||
public:
|
||||
TargetException(const std::string r) : ExceptionBase(), reason(r) { }
|
||||
virtual const char* what(void) const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace exception */
|
||||
} /* namespace fuzzing */
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <optional>
|
||||
|
||||
#ifndef ASAN
|
||||
#define ASAN 0
|
||||
#endif
|
||||
|
||||
#ifndef MSAN
|
||||
#define MSAN 0
|
||||
#endif
|
||||
|
||||
namespace fuzzing {
|
||||
namespace memory {
|
||||
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
#if ASAN == 1
|
||||
extern "C" void *__asan_region_is_poisoned(const void *beg, size_t size);
|
||||
#endif
|
||||
|
||||
#if MSAN == 1
|
||||
extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
|
||||
#endif
|
||||
|
||||
void memory_test_asan(const void* data, const size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
|
||||
#if ASAN == 1
|
||||
if ( __asan_region_is_poisoned(data, size) != NULL ) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void memory_test_msan(const void* data, const size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
|
||||
#if MSAN == 1
|
||||
__msan_check_mem_is_initialized(data, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void memory_test(const void* data, const size_t size)
|
||||
{
|
||||
memory_test_asan(data, size);
|
||||
memory_test_msan(data, size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void memory_test(const T& t)
|
||||
{
|
||||
(void)t;
|
||||
}
|
||||
|
||||
template <>
|
||||
void memory_test(const std::string& s)
|
||||
{
|
||||
(void)s;
|
||||
|
||||
#if MSAN == 1
|
||||
memory_test(s.data(), s.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} /* namespace memory */
|
||||
} /* namespace fuzzing */
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fuzzing/memory.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace fuzzing {
|
||||
namespace types {
|
||||
|
||||
template <typename CoreType, bool NullTerminated, bool UseMSAN = false>
|
||||
class Container {
|
||||
private:
|
||||
CoreType* InvalidAddress = (CoreType*)0x12;
|
||||
|
||||
CoreType* _data = InvalidAddress;
|
||||
size_t _size = 0;
|
||||
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
void copy(const void* data, size_t size) {
|
||||
if ( size > 0 ) {
|
||||
std::memcpy(_data, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
void allocate(size_t size) {
|
||||
if ( size > 0 ) {
|
||||
_data = static_cast<CoreType*>(malloc(size * sizeof(CoreType)));
|
||||
} else {
|
||||
_data = InvalidAddress;
|
||||
}
|
||||
};
|
||||
|
||||
void allocate_and_copy(const void* data, size_t size) {
|
||||
allocate(size);
|
||||
copy(data, size);
|
||||
}
|
||||
|
||||
void allocate_plus_1_and_copy(const void* data, size_t size) {
|
||||
allocate(size+1);
|
||||
copy(data, size);
|
||||
}
|
||||
|
||||
void access_hook(void) const {
|
||||
if ( UseMSAN == true ) {
|
||||
memory::memory_test_msan(_data, _size);
|
||||
}
|
||||
}
|
||||
|
||||
void free(void) {
|
||||
access_hook();
|
||||
|
||||
if ( _data != InvalidAddress ) {
|
||||
std::free(_data);
|
||||
_data = InvalidAddress;
|
||||
_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
CoreType* data(void) {
|
||||
access_hook();
|
||||
return _data;
|
||||
}
|
||||
|
||||
size_t size(void) const {
|
||||
access_hook();
|
||||
return _size;
|
||||
}
|
||||
#endif
|
||||
|
||||
Container(void)
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
= default
|
||||
#endif
|
||||
;
|
||||
|
||||
Container(const void* data, const size_t size)
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
{
|
||||
if ( NullTerminated == false ) {
|
||||
allocate_and_copy(data, size);
|
||||
} else {
|
||||
allocate_plus_1_and_copy(data, size);
|
||||
_data[size] = 0;
|
||||
}
|
||||
|
||||
access_hook();
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
template<class T>
|
||||
Container(const T& t)
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
{
|
||||
Container(t.data(), t.size());
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
~Container(void)
|
||||
#ifndef FUZZING_HEADERS_NO_IMPL
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
|
||||
// The copy constructor was not originally explicitly supplied
|
||||
// so it must have been incorrectly just copying the pointers.
|
||||
Container(const Container &c) {
|
||||
InvalidAddress = c.InvalidAddress;
|
||||
allocate_and_copy(c._data, c._size);
|
||||
}
|
||||
|
||||
Container& operator=(Container &c) {
|
||||
InvalidAddress = c.InvalidAddress;
|
||||
allocate_and_copy(c._data, c._size);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <bool UseMSAN = false> using String = Container<char, true, UseMSAN>;
|
||||
template <bool UseMSAN = false> using Data = Container<uint8_t, false, UseMSAN>;
|
||||
|
||||
} /* namespace types */
|
||||
} /* namespace fuzzing */
|
||||
Vendored
+526
@@ -0,0 +1,526 @@
|
||||
/* fuzzer_metadata
|
||||
* Copyright (C) 2022-2023 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the Xiph.org Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring> /* for memcpy */
|
||||
#include <unistd.h>
|
||||
#include "FLAC++/metadata.h"
|
||||
#include "common.h"
|
||||
|
||||
#define CONFIG_LENGTH 2
|
||||
|
||||
#define min(x,y) (x<y?x:y)
|
||||
|
||||
static void run_tests_with_level_0_interface(char filename[]);
|
||||
static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size);
|
||||
static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size);
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
uint8_t command_length;
|
||||
char filename[] = "/tmp/tmpXXXXXX.flac";
|
||||
FLAC__bool init_bools[4];
|
||||
|
||||
/* Use first byte for configuration, leave at least one byte of input */
|
||||
if(size < 1 + CONFIG_LENGTH){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First 4 bits for configuration bools, next 4 for length of command section */
|
||||
for(int i = 0; i < 4; i++)
|
||||
init_bools[i] = data[i/8] & (1 << (i % 8));
|
||||
|
||||
command_length = data[0] >> 4;
|
||||
|
||||
if(0)//data[1] < 128) /* Use MSB as on/off */
|
||||
alloc_check_threshold = data[1];
|
||||
else
|
||||
alloc_check_threshold = INT32_MAX;
|
||||
alloc_check_counter = 0;
|
||||
|
||||
|
||||
/* Leave at least one byte as input */
|
||||
if(command_length >= size - 1 - CONFIG_LENGTH)
|
||||
command_length = size - 1 - CONFIG_LENGTH;
|
||||
|
||||
/* Dump input to file */
|
||||
{
|
||||
int file_to_fuzz = mkstemps(filename, 5);
|
||||
|
||||
if (file_to_fuzz < 0)
|
||||
abort();
|
||||
write(file_to_fuzz,data+CONFIG_LENGTH+command_length,size-CONFIG_LENGTH-command_length);
|
||||
close(file_to_fuzz);
|
||||
}
|
||||
|
||||
run_tests_with_level_0_interface(filename);
|
||||
run_tests_with_level_1_interface(filename, init_bools[1], init_bools[2], data+CONFIG_LENGTH, command_length/2);
|
||||
|
||||
/* Dump input to file, to start fresh for level 2 */
|
||||
if(!init_bools[1]){
|
||||
FILE * file_to_fuzz = fopen(filename,"w");
|
||||
fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_fuzz);
|
||||
fclose(file_to_fuzz);
|
||||
}
|
||||
|
||||
run_tests_with_level_2_interface(filename, init_bools[0], init_bools[3], data+command_length/2+CONFIG_LENGTH, command_length/2);
|
||||
|
||||
remove(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_tests_with_level_0_interface(char filename[]) {
|
||||
FLAC::Metadata::StreamInfo streaminfo;
|
||||
FLAC::Metadata::VorbisComment vorbis_comment;
|
||||
FLAC::Metadata::CueSheet cue_sheet;
|
||||
FLAC::Metadata::Picture picture;
|
||||
|
||||
FLAC::Metadata::get_streaminfo(filename,streaminfo);
|
||||
FLAC::Metadata::get_tags(filename,vorbis_comment);
|
||||
FLAC::Metadata::get_cuesheet(filename,cue_sheet);
|
||||
FLAC::Metadata::get_picture(filename,picture, (FLAC__StreamMetadata_Picture_Type)(1), NULL, NULL, -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
static void run_tests_with_level_1_interface(char filename[], bool readonly, bool preservestats, const uint8_t *data, size_t size) {
|
||||
FLAC::Metadata::SimpleIterator iterator;
|
||||
FLAC::Metadata::Prototype *metadata_block = nullptr;
|
||||
uint8_t id[4] = {0};
|
||||
|
||||
if(!iterator.is_valid())
|
||||
return;
|
||||
|
||||
if(!iterator.init(filename,readonly,preservestats))
|
||||
return;
|
||||
|
||||
for(size_t i = 0; i < size && iterator.status() == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; i++) {
|
||||
switch(data[i] & 7) {
|
||||
case 0:
|
||||
iterator.get_block_type();
|
||||
iterator.get_block_offset();
|
||||
iterator.get_block_length();
|
||||
iterator.get_application_id(id);
|
||||
break;
|
||||
case 1:
|
||||
iterator.next();
|
||||
break;
|
||||
case 2:
|
||||
iterator.prev();
|
||||
break;
|
||||
case 3:
|
||||
iterator.delete_block(data[i] & 8);
|
||||
break;
|
||||
case 4:
|
||||
if(metadata_block != 0) {
|
||||
delete metadata_block;
|
||||
metadata_block = nullptr;
|
||||
}
|
||||
metadata_block = iterator.get_block();
|
||||
break;
|
||||
case 5:
|
||||
if(metadata_block != 0)
|
||||
iterator.set_block(metadata_block,data[i] & 8);
|
||||
break;
|
||||
case 6:
|
||||
if(metadata_block != 0)
|
||||
iterator.insert_block_after(metadata_block, data[i] & 8);
|
||||
break;
|
||||
case 7:
|
||||
iterator.status();
|
||||
iterator.is_last();
|
||||
iterator.is_writable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(metadata_block != 0) {
|
||||
delete metadata_block;
|
||||
metadata_block = nullptr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void run_tests_with_level_2_interface(char filename[], bool ogg, bool use_padding, const uint8_t *data, size_t size) {
|
||||
FLAC::Metadata::Chain chain;
|
||||
FLAC::Metadata::Iterator iterator;
|
||||
FLAC::Metadata::Prototype *metadata_block_get = nullptr;
|
||||
FLAC::Metadata::Prototype *metadata_block_transfer = nullptr;
|
||||
FLAC::Metadata::Prototype *metadata_block_put = nullptr;
|
||||
|
||||
if(!chain.is_valid())
|
||||
return;
|
||||
|
||||
if(!chain.read(filename, ogg))
|
||||
return;
|
||||
|
||||
iterator.init(chain);
|
||||
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
switch(data[i] & 15) {
|
||||
case 0:
|
||||
iterator.get_block_type();
|
||||
break;
|
||||
case 1:
|
||||
iterator.next();
|
||||
break;
|
||||
case 2:
|
||||
iterator.prev();
|
||||
break;
|
||||
case 3:
|
||||
iterator.delete_block(data[i] & 16);
|
||||
break;
|
||||
case 4:
|
||||
metadata_block_get = iterator.get_block();
|
||||
if(metadata_block_get != 0 && metadata_block_get->is_valid()) {
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
if(metadata_block_transfer != metadata_block_get) {
|
||||
delete metadata_block_transfer;
|
||||
metadata_block_transfer = nullptr;
|
||||
metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
|
||||
}
|
||||
}
|
||||
else {
|
||||
metadata_block_transfer = FLAC::Metadata::clone(metadata_block_get);
|
||||
}
|
||||
}
|
||||
delete metadata_block_get;
|
||||
break;
|
||||
case 5:
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
|
||||
if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
|
||||
if(!iterator.insert_block_before(metadata_block_put))
|
||||
delete metadata_block_put;
|
||||
}
|
||||
else
|
||||
if(metadata_block_put != 0)
|
||||
delete metadata_block_put;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
|
||||
if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
|
||||
if(!iterator.insert_block_after(metadata_block_put))
|
||||
delete metadata_block_put;
|
||||
}
|
||||
else
|
||||
if(metadata_block_put != 0)
|
||||
delete metadata_block_put;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
metadata_block_put = FLAC::Metadata::clone(metadata_block_transfer);
|
||||
if(metadata_block_put != 0 && metadata_block_put->is_valid()) {
|
||||
if(!iterator.set_block(metadata_block_put))
|
||||
delete metadata_block_put;
|
||||
}
|
||||
else
|
||||
if(metadata_block_put != 0)
|
||||
delete metadata_block_put;
|
||||
}
|
||||
break;
|
||||
case 8: /* Examine block */
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
switch(metadata_block_transfer->get_type()) {
|
||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||
{
|
||||
uint32_t num_comments;
|
||||
::FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
FLAC::Metadata::VorbisComment::Entry entry_cpp;
|
||||
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
|
||||
const ::FLAC__StreamMetadata * metadata_c = *metadata_block_transfer;
|
||||
if(vorbiscomment == 0)
|
||||
abort();
|
||||
vorbiscomment->get_vendor_string();
|
||||
num_comments = vorbiscomment->get_num_comments();
|
||||
if(num_comments > 0) {
|
||||
entry = metadata_c->data.vorbis_comment.comments[min(data[i]>>4,num_comments-1)];
|
||||
if(entry.entry == 0)
|
||||
abort();
|
||||
if(vorbiscomment->get_comment(min(data[i]>>4,num_comments-1)).is_valid()) {
|
||||
entry_cpp = vorbiscomment->get_comment(min(data[i]>>4,num_comments-1));
|
||||
if(entry_cpp.is_valid() && entry_cpp.get_field() == 0)
|
||||
abort();
|
||||
vorbiscomment->find_entry_from(0,"TEST");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_CUESHEET:
|
||||
{
|
||||
uint32_t num_tracks, num_indices;
|
||||
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
|
||||
if(cuesheet == 0 || !cuesheet->is_legal())
|
||||
break;
|
||||
cuesheet->is_legal(true); /* check CDDA subset */
|
||||
cuesheet->calculate_cddb_id();
|
||||
cuesheet->get_media_catalog_number();
|
||||
cuesheet->get_lead_in();
|
||||
cuesheet->get_is_cd();
|
||||
num_tracks = cuesheet->get_num_tracks();
|
||||
if(num_tracks > 0) {
|
||||
FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
|
||||
track.get_offset();
|
||||
track.get_number();
|
||||
track.get_isrc();
|
||||
track.get_pre_emphasis();
|
||||
num_indices = track.get_num_indices();
|
||||
if(num_indices > 0) {
|
||||
FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
|
||||
(void)index;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_PICTURE:
|
||||
{
|
||||
char * violation = nullptr;
|
||||
FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
|
||||
if(picture == 0 || !picture->is_legal((const char **)&violation))
|
||||
break;
|
||||
picture->get_data();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 9: /* Replace or add in block */
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
switch(metadata_block_transfer->get_type()) {
|
||||
case FLAC__METADATA_TYPE_SEEKTABLE:
|
||||
{
|
||||
uint32_t num_seekpoints;
|
||||
FLAC__StreamMetadata_SeekPoint seekpoint;
|
||||
FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
|
||||
if(seektable == 0)
|
||||
break;
|
||||
if(seektable->is_valid() && seektable->is_legal()) {
|
||||
num_seekpoints = seektable->get_num_points();
|
||||
if(num_seekpoints > 0) {
|
||||
seekpoint = seektable->get_point(min(data[i]>>5,num_seekpoints-1));
|
||||
seektable->set_point(0,seekpoint);
|
||||
seektable->insert_point(min(data[i]>>5,num_seekpoints-1),seekpoint);
|
||||
}
|
||||
seektable->template_append_placeholders(4);
|
||||
seektable->template_append_point(111111);
|
||||
seektable->template_append_points((FLAC__uint64[]){222222, 333333, 444444}, 3);
|
||||
seektable->template_append_spaced_points(data[i]>>5, 1234567);
|
||||
seektable->template_append_spaced_points_by_samples(data[i]>>5, 2468000);
|
||||
seektable->template_sort(data[i] & 16);
|
||||
}
|
||||
}
|
||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||
{
|
||||
uint32_t num_comments;
|
||||
FLAC::Metadata::VorbisComment::Entry entry;
|
||||
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
|
||||
if(vorbiscomment == 0)
|
||||
break;
|
||||
num_comments = vorbiscomment->get_num_comments();
|
||||
if(num_comments > 0 && entry.is_valid()) {
|
||||
if(vorbiscomment->get_comment(min(data[i]>>5,num_comments-1)).is_valid()) {
|
||||
entry = vorbiscomment->get_comment(min(data[i]>>5,num_comments-1));
|
||||
if(entry.is_valid()) {
|
||||
vorbiscomment->replace_comment(entry,data[i] & 16);
|
||||
vorbiscomment->set_comment(0,entry);
|
||||
vorbiscomment->append_comment(entry);
|
||||
vorbiscomment->insert_comment(0,entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_CUESHEET:
|
||||
{
|
||||
uint32_t num_tracks, num_indices;
|
||||
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
|
||||
if(cuesheet == 0 || !cuesheet->is_legal())
|
||||
break;
|
||||
num_tracks = cuesheet->get_num_tracks();
|
||||
if(num_tracks > 0) {
|
||||
FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
|
||||
num_indices = track.get_num_indices();
|
||||
if(num_indices > 0) {
|
||||
FLAC__StreamMetadata_CueSheet_Index index = track.get_index(min(data[i]>>4,num_indices-1));
|
||||
track.set_index(0,index);
|
||||
cuesheet->insert_index(0,0,index);
|
||||
cuesheet->insert_blank_index(0,0);
|
||||
}
|
||||
cuesheet->insert_blank_track(0);
|
||||
cuesheet->insert_track(0,track);
|
||||
cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_PICTURE:
|
||||
{
|
||||
FLAC::Metadata::Picture * picture = dynamic_cast<FLAC::Metadata::Picture *>(metadata_block_transfer);
|
||||
const char testtext[] = "TEST";
|
||||
if(picture == 0 || !picture->is_legal(NULL))
|
||||
break;
|
||||
picture->set_description((FLAC__byte *)&testtext);
|
||||
picture->set_mime_type((const char *)&testtext);
|
||||
picture->set_data((FLAC__byte *)&testtext,4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 10: /* Delete from block */
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
switch(metadata_block_transfer->get_type()) {
|
||||
case FLAC__METADATA_TYPE_SEEKTABLE:
|
||||
{
|
||||
uint32_t num_seekpoints;
|
||||
FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
|
||||
if(seektable == 0)
|
||||
break;
|
||||
if(seektable->is_valid() && seektable->is_legal()) {
|
||||
num_seekpoints = seektable->get_num_points();
|
||||
if(num_seekpoints > 0)
|
||||
seektable->delete_point(min(data[i]>>4,num_seekpoints-1));
|
||||
}
|
||||
}
|
||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||
{
|
||||
uint32_t num_comments;
|
||||
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
|
||||
if(vorbiscomment == 0)
|
||||
break;
|
||||
num_comments = vorbiscomment->get_num_comments();
|
||||
if(num_comments > 0)
|
||||
vorbiscomment->delete_comment(min(data[i]>>4,num_comments-1));
|
||||
vorbiscomment->remove_entry_matching("TEST");
|
||||
vorbiscomment->remove_entries_matching("TEST");
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_CUESHEET:
|
||||
{
|
||||
uint32_t num_tracks;
|
||||
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
|
||||
if(cuesheet == 0 || !cuesheet->is_legal())
|
||||
break;
|
||||
num_tracks = cuesheet->get_num_tracks();
|
||||
if(num_tracks > 0) {
|
||||
FLAC::Metadata::CueSheet::Track track = cuesheet->get_track(min(data[i]>>4,num_tracks-1));
|
||||
if(track.get_num_indices() > 0)
|
||||
cuesheet->delete_index(min(data[i]>>4,num_tracks-1),0);
|
||||
cuesheet->delete_track(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 11: /* Resize block */
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
switch(metadata_block_transfer->get_type()) {
|
||||
case FLAC__METADATA_TYPE_PADDING:
|
||||
{
|
||||
FLAC::Metadata::Padding * padding = dynamic_cast<FLAC::Metadata::Padding *>(metadata_block_transfer);
|
||||
if(padding == 0)
|
||||
break;
|
||||
padding->set_length(data[i]>>4);
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_SEEKTABLE:
|
||||
{
|
||||
FLAC::Metadata::SeekTable * seektable = dynamic_cast<FLAC::Metadata::SeekTable *>(metadata_block_transfer);
|
||||
if(seektable == 0)
|
||||
break;
|
||||
seektable->resize_points(data[i]>>4);
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||
{
|
||||
FLAC::Metadata::VorbisComment * vorbiscomment = dynamic_cast<FLAC::Metadata::VorbisComment *>(metadata_block_transfer);
|
||||
if(vorbiscomment == 0)
|
||||
break;
|
||||
vorbiscomment->resize_comments(data[i]>>4);
|
||||
}
|
||||
break;
|
||||
case FLAC__METADATA_TYPE_CUESHEET:
|
||||
{
|
||||
uint32_t num_tracks;
|
||||
FLAC::Metadata::CueSheet * cuesheet = dynamic_cast<FLAC::Metadata::CueSheet *>(metadata_block_transfer);
|
||||
if(cuesheet == 0 || !cuesheet->is_legal())
|
||||
break;
|
||||
num_tracks = cuesheet->get_num_tracks();
|
||||
if(num_tracks > 0) {
|
||||
cuesheet->resize_indices(min(data[i]>>4,num_tracks-1),data[i]>>4);
|
||||
}
|
||||
cuesheet->resize_tracks(data[i]<<4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 12: /* Prototype functions */
|
||||
if(metadata_block_transfer != 0 && metadata_block_transfer->is_valid()) {
|
||||
const ::FLAC__StreamMetadata * metadata_compare = *metadata_block_transfer;
|
||||
metadata_block_transfer->get_is_last();
|
||||
metadata_block_transfer->get_length();
|
||||
metadata_block_transfer->set_is_last(data[i] & 16);
|
||||
FLAC__metadata_object_is_equal(metadata_compare, metadata_compare);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(metadata_block_transfer != 0) {
|
||||
delete metadata_block_transfer;
|
||||
metadata_block_transfer = nullptr;
|
||||
}
|
||||
|
||||
chain.status();
|
||||
chain.sort_padding();
|
||||
chain.merge_padding();
|
||||
|
||||
chain.check_if_tempfile_needed(!use_padding);
|
||||
chain.write(use_padding);
|
||||
|
||||
}
|
||||
Vendored
+304
@@ -0,0 +1,304 @@
|
||||
/* Copyright 2019 Guido Vranken
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject
|
||||
* to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include <fuzzing/datasource/datasource.hpp>
|
||||
#include <fuzzing/memory.hpp>
|
||||
|
||||
#include "FLAC++/encoder.h"
|
||||
#include "FLAC++/decoder.h"
|
||||
#include "FLAC++/metadata.h"
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_NUM_METADATA_BLOCKS 2048
|
||||
|
||||
namespace FLAC {
|
||||
namespace Encoder {
|
||||
class FuzzerStream : public Stream {
|
||||
private:
|
||||
// fuzzing::datasource::Datasource& ds;
|
||||
public:
|
||||
FuzzerStream(fuzzing::datasource::Datasource&) :
|
||||
Stream() { }
|
||||
|
||||
::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, uint32_t /* samples */, uint32_t /* current_frame */) override {
|
||||
fuzzing::memory::memory_test(buffer, bytes);
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||
}
|
||||
};
|
||||
}
|
||||
namespace Decoder {
|
||||
class FuzzerDecoder : public Stream {
|
||||
private:
|
||||
fuzzing::datasource::Datasource& ds;
|
||||
FLAC::Encoder::FuzzerStream& encoder;
|
||||
public:
|
||||
FuzzerDecoder(fuzzing::datasource::Datasource& dsrc, FLAC::Encoder::FuzzerStream& encoder_arg) :
|
||||
Stream(), ds(dsrc), encoder(encoder_arg) { }
|
||||
|
||||
::FLAC__StreamMetadata * metadata_blocks[MAX_NUM_METADATA_BLOCKS] = {0};
|
||||
int num_metadata_blocks = 0;
|
||||
|
||||
void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
|
||||
if(num_metadata_blocks < MAX_NUM_METADATA_BLOCKS)
|
||||
if((metadata_blocks[num_metadata_blocks] = FLAC__metadata_object_clone(metadata)) != NULL)
|
||||
num_metadata_blocks++;
|
||||
}
|
||||
|
||||
::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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Data is checked, now pass it towards encoder */
|
||||
if(encoder.get_state() == FLAC__STREAM_ENCODER_OK) {
|
||||
if(encoder.get_channels() != get_channels())
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
if(encoder.get_bits_per_sample() != get_bits_per_sample())
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
encoder.process(buffer, frame->header.blocksize);
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
void error_callback(::FLAC__StreamDecoderErrorStatus status) override {
|
||||
fuzzing::memory::memory_test(status);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
fuzzing::datasource::Datasource ds(data, size);
|
||||
FLAC::Encoder::FuzzerStream encoder(ds);
|
||||
FLAC::Decoder::FuzzerDecoder decoder(ds, encoder);
|
||||
|
||||
try {
|
||||
const int channels = ds.Get<uint8_t>();
|
||||
const int bps = ds.Get<uint8_t>();
|
||||
encoder.set_channels(channels);
|
||||
encoder.set_bits_per_sample(bps);
|
||||
|
||||
{
|
||||
const bool res = encoder.set_streamable_subset(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_ogg_serial_number(ds.Get<long>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_verify(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_compression_level(ds.Get<uint8_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_do_mid_side_stereo(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_loose_mid_side_stereo(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_max_lpc_order(ds.Get<uint8_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_qlp_coeff_precision(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_do_escape_coding(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_min_residual_partition_order(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_max_residual_partition_order(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_total_samples_estimate(ds.Get<uint64_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_blocksize(ds.Get<uint16_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_limit_min_bitrate(ds.Get<bool>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = encoder.set_sample_rate(ds.Get<uint32_t>());
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
|
||||
decoder.set_metadata_respond_all();
|
||||
|
||||
{
|
||||
::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;
|
||||
}
|
||||
|
||||
decoder.process_until_end_of_metadata();
|
||||
if(decoder.num_metadata_blocks > 0)
|
||||
encoder.set_metadata(decoder.metadata_blocks, decoder.num_metadata_blocks);
|
||||
}
|
||||
|
||||
{
|
||||
::FLAC__StreamEncoderInitStatus ret;
|
||||
if ( ds.Get<bool>() ) {
|
||||
ret = encoder.init();
|
||||
} else {
|
||||
ret = encoder.init_ogg();
|
||||
}
|
||||
|
||||
if ( ret != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* These sets must fail, because encoder is already initialized */
|
||||
{
|
||||
bool res = false;
|
||||
res = res || encoder.set_streamable_subset(true);
|
||||
res = res || encoder.set_ogg_serial_number(0);
|
||||
res = res || encoder.set_verify(true);
|
||||
res = res || encoder.set_compression_level(0);
|
||||
res = res || encoder.set_do_exhaustive_model_search(true);
|
||||
res = res || encoder.set_do_mid_side_stereo(true);
|
||||
res = res || encoder.set_loose_mid_side_stereo(true);
|
||||
res = res || encoder.set_apodization("test");
|
||||
res = res || encoder.set_max_lpc_order(0);
|
||||
res = res || encoder.set_qlp_coeff_precision(0);
|
||||
res = res || encoder.set_do_qlp_coeff_prec_search(true);
|
||||
res = res || encoder.set_do_escape_coding(true);
|
||||
res = res || encoder.set_min_residual_partition_order(0);
|
||||
res = res || encoder.set_max_residual_partition_order(0);
|
||||
res = res || encoder.set_rice_parameter_search_dist(0);
|
||||
res = res || encoder.set_total_samples_estimate(0);
|
||||
res = res || encoder.set_channels(channels);
|
||||
res = res || encoder.set_bits_per_sample(16);
|
||||
res = res || encoder.set_limit_min_bitrate(true);
|
||||
res = res || encoder.set_blocksize(3021);
|
||||
res = res || encoder.set_sample_rate(44100);
|
||||
fuzzing::memory::memory_test(res);
|
||||
if(res)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/* XORing values as otherwise compiler will optimize, apparently */
|
||||
bool res = false;
|
||||
res = res != encoder.get_streamable_subset();
|
||||
res = res != encoder.get_verify();
|
||||
res = res != encoder.get_do_exhaustive_model_search();
|
||||
res = res != encoder.get_do_mid_side_stereo();
|
||||
res = res != encoder.get_loose_mid_side_stereo();
|
||||
res = res != encoder.get_max_lpc_order();
|
||||
res = res != encoder.get_qlp_coeff_precision();
|
||||
res = res != encoder.get_do_qlp_coeff_prec_search();
|
||||
res = res != encoder.get_do_escape_coding();
|
||||
res = res != encoder.get_min_residual_partition_order();
|
||||
res = res != encoder.get_max_residual_partition_order();
|
||||
res = res != encoder.get_rice_parameter_search_dist();
|
||||
res = res != encoder.get_total_samples_estimate();
|
||||
res = res != encoder.get_channels();
|
||||
res = res != encoder.get_bits_per_sample();
|
||||
res = res != encoder.get_limit_min_bitrate();
|
||||
res = res != encoder.get_blocksize();
|
||||
res = res != encoder.get_sample_rate();
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
|
||||
decoder.process_until_end_of_stream();
|
||||
|
||||
} catch ( ... ) { }
|
||||
|
||||
end:
|
||||
{
|
||||
const bool res = encoder.finish();
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
{
|
||||
const bool res = decoder.finish();
|
||||
fuzzing::memory::memory_test(res);
|
||||
}
|
||||
for(int i = 0; i < decoder.num_metadata_blocks; i++)
|
||||
FLAC__metadata_object_delete(decoder.metadata_blocks[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
+195
@@ -0,0 +1,195 @@
|
||||
/* fuzzer_seek
|
||||
* Copyright (C) 2022-2023 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the Xiph.org Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring> /* for memcpy */
|
||||
#include "FLAC/stream_decoder.h"
|
||||
#include "common.h"
|
||||
|
||||
int write_abort_check_counter = -1;
|
||||
|
||||
#if 0 /* set to 1 to debug */
|
||||
#define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__)
|
||||
#else
|
||||
#define FPRINTF_DEBUG_ONLY(...)
|
||||
#endif
|
||||
|
||||
#define CONFIG_LENGTH 2
|
||||
|
||||
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
|
||||
{
|
||||
(void)decoder, (void)frame, (void)buffer, (void)client_data;
|
||||
if(write_abort_check_counter > 0) {
|
||||
write_abort_check_counter--;
|
||||
if(write_abort_check_counter == 0)
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
} else if(write_abort_check_counter == 0)
|
||||
/* This must not happen: write callback called after abort is returned */
|
||||
abort();
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus error, void *client_data)
|
||||
{
|
||||
(void)decoder, (void)error, (void)client_data;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
FLAC__bool decoder_valid = true;
|
||||
FLAC__StreamDecoder *decoder;
|
||||
uint8_t command_length;
|
||||
FLAC__bool init_bools[16], ogg;
|
||||
|
||||
if(size > 2 && data[1] < 128) /* Use MSB as on/off */
|
||||
alloc_check_threshold = data[1];
|
||||
else
|
||||
alloc_check_threshold = INT32_MAX;
|
||||
alloc_check_counter = 0;
|
||||
|
||||
write_abort_check_counter = -1;
|
||||
|
||||
/* allocate the decoder */
|
||||
if((decoder = FLAC__stream_decoder_new()) == NULL) {
|
||||
fprintf(stderr, "ERROR: allocating decoder\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Use first byte for configuration, leave at least one byte of input */
|
||||
if(size < 1 + CONFIG_LENGTH){
|
||||
FLAC__stream_decoder_delete(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First 4 bits for configuration bools, next 4 for length of command section */
|
||||
for(int i = 0; i < 4; i++)
|
||||
init_bools[i] = data[i/8] & (1 << (i % 8));
|
||||
|
||||
command_length = data[0] >> 4;
|
||||
|
||||
/* Leave at least one byte as input */
|
||||
if(command_length >= size - 1 - CONFIG_LENGTH)
|
||||
command_length = size - 1 - CONFIG_LENGTH;
|
||||
|
||||
/* Dump decoder input to file */
|
||||
{
|
||||
FILE * file_to_decode = fopen("/tmp/tmp.flac","w");
|
||||
fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_decode);
|
||||
fclose(file_to_decode);
|
||||
}
|
||||
|
||||
ogg = init_bools[0];
|
||||
|
||||
FLAC__stream_decoder_set_md5_checking(decoder,init_bools[1]);
|
||||
if(init_bools[2])
|
||||
FLAC__stream_decoder_set_metadata_respond_all(decoder);
|
||||
if(init_bools[3])
|
||||
FLAC__stream_decoder_set_metadata_ignore_all(decoder);
|
||||
|
||||
/* initialize decoder */
|
||||
if(decoder_valid) {
|
||||
FLAC__StreamDecoderInitStatus init_status;
|
||||
if(ogg)
|
||||
init_status = FLAC__stream_decoder_init_ogg_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL);
|
||||
else
|
||||
init_status = FLAC__stream_decoder_init_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL);
|
||||
if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
|
||||
decoder_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run commands */
|
||||
for(uint8_t i = 0; decoder_valid && (i < command_length); i++){
|
||||
const uint8_t * command = data+CONFIG_LENGTH+i;
|
||||
uint8_t shift = 1u << (command[0] >> 3);
|
||||
FLAC__uint64 seekpos;
|
||||
|
||||
switch(command[0] & 15){
|
||||
case 0:
|
||||
FPRINTF_DEBUG_ONLY(stderr,"end_of_stream\n");
|
||||
decoder_valid = FLAC__stream_decoder_process_until_end_of_stream(decoder);
|
||||
break;
|
||||
case 1:
|
||||
FPRINTF_DEBUG_ONLY(stderr,"end_of_metadata\n");
|
||||
decoder_valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder);
|
||||
break;
|
||||
case 2:
|
||||
FPRINTF_DEBUG_ONLY(stderr,"single\n");
|
||||
decoder_valid = FLAC__stream_decoder_process_single(decoder);
|
||||
break;
|
||||
case 3:
|
||||
FPRINTF_DEBUG_ONLY(stderr,"skip_single\n");
|
||||
decoder_valid = FLAC__stream_decoder_skip_single_frame(decoder);
|
||||
break;
|
||||
case 4:
|
||||
FPRINTF_DEBUG_ONLY(stderr,"reset\n");
|
||||
decoder_valid = FLAC__stream_decoder_reset(decoder);
|
||||
break;
|
||||
case 5:
|
||||
FPRINTF_DEBUG_ONLY(stderr,"flush\n");
|
||||
decoder_valid = FLAC__stream_decoder_flush(decoder);
|
||||
break;
|
||||
case 6:
|
||||
case 14:
|
||||
shift = 1u << (command[0] >> 3);
|
||||
FPRINTF_DEBUG_ONLY(stderr,"seek short %hhu\n",shift);
|
||||
decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,shift);
|
||||
break;
|
||||
case 7:
|
||||
if(i+8 >= command_length) /* Not enough data available to do this */
|
||||
break;
|
||||
seekpos = ((FLAC__uint64)command[1] << 56) +
|
||||
((FLAC__uint64)command[2] << 48) +
|
||||
((FLAC__uint64)command[3] << 40) +
|
||||
((FLAC__uint64)command[4] << 32) +
|
||||
((FLAC__uint64)command[5] << 24) +
|
||||
((FLAC__uint64)command[6] << 16) +
|
||||
((FLAC__uint64)command[7] << 8) +
|
||||
command[8];
|
||||
i+=8;
|
||||
FPRINTF_DEBUG_ONLY(stderr,"seek long %lu\n",seekpos);
|
||||
decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,seekpos);
|
||||
break;
|
||||
case 8:
|
||||
/* Set abort on write callback */
|
||||
write_abort_check_counter = (command[0] >> 4) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__stream_decoder_finish(decoder);
|
||||
|
||||
FLAC__stream_decoder_delete(decoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vendored
+117
@@ -0,0 +1,117 @@
|
||||
/* fuzzer_tool_flac
|
||||
* Copyright (C) 2023 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the Xiph.org Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* for memcpy */
|
||||
#define FUZZ_TOOL_FLAC
|
||||
#define fprintf(...)
|
||||
#define printf(...)
|
||||
#include "../src/flac/main.c"
|
||||
#include "common.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
size_t size_left = size;
|
||||
size_t arglen;
|
||||
char * argv[67];
|
||||
char exename[] = "flac";
|
||||
char filename[] = "/tmp/fuzzXXXXXX";
|
||||
int numarg = 0, maxarg;
|
||||
int file_to_fuzz;
|
||||
int tmp_stdout, tmp_stdin;
|
||||
fpos_t pos_stdout;
|
||||
bool use_stdin = false;
|
||||
|
||||
/* reset global vars */
|
||||
flac__utils_verbosity_ = 0;
|
||||
share__opterr = 0;
|
||||
share__optind = 0;
|
||||
|
||||
if(size < 2)
|
||||
return 0;
|
||||
|
||||
maxarg = data[0] & 63;
|
||||
use_stdin = data[0] & 64;
|
||||
size_left--;
|
||||
|
||||
argv[0] = exename;
|
||||
numarg++;
|
||||
|
||||
/* Check whether input is zero delimited */
|
||||
while((arglen = strnlen((char *)data+(size-size_left),size_left)) < size_left && numarg < maxarg) {
|
||||
argv[numarg++] = (char *)data+(size-size_left);
|
||||
size_left -= arglen + 1;
|
||||
}
|
||||
|
||||
file_to_fuzz = mkstemp(filename);
|
||||
|
||||
if (file_to_fuzz < 0)
|
||||
abort();
|
||||
write(file_to_fuzz,data+(size-size_left),size_left);
|
||||
close(file_to_fuzz);
|
||||
|
||||
/* redirect stdout */
|
||||
fflush(stdout);
|
||||
fgetpos(stdout,&pos_stdout);
|
||||
tmp_stdout = dup(fileno(stdout));
|
||||
freopen("/dev/null","w",stdout);
|
||||
|
||||
/* redirect stdin */
|
||||
tmp_stdin = dup(fileno(stdin));
|
||||
|
||||
if(use_stdin)
|
||||
freopen(filename,"r",stdin);
|
||||
else {
|
||||
freopen("/dev/null","r",stdin);
|
||||
argv[numarg++] = filename;
|
||||
}
|
||||
|
||||
main_to_fuzz(numarg,argv);
|
||||
|
||||
/* restore stdout */
|
||||
fflush(stdout);
|
||||
dup2(tmp_stdout, fileno(stdout));
|
||||
close(tmp_stdout);
|
||||
clearerr(stdout);
|
||||
fsetpos(stdout,&pos_stdout);
|
||||
|
||||
/* restore stdin */
|
||||
dup2(tmp_stdin, fileno(stdin));
|
||||
close(tmp_stdin);
|
||||
clearerr(stdin);
|
||||
|
||||
unlink(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vendored
+136
@@ -0,0 +1,136 @@
|
||||
/* fuzzer_tool_flac
|
||||
* Copyright (C) 2023 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the Xiph.org Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* for memcpy */
|
||||
#define FUZZ_TOOL_METAFLAC
|
||||
#define fprintf(...)
|
||||
#define printf(...)
|
||||
#include "../src/metaflac/main.c"
|
||||
#include "common.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
size_t size_left = size;
|
||||
size_t arglen;
|
||||
char * argv[64];
|
||||
char exename[] = "metaflac";
|
||||
char filename[] = "/tmp/fuzzXXXXXX";
|
||||
char filename_stdin[] = "/tmp/fuzzXXXXXX";
|
||||
int numarg = 0, maxarg;
|
||||
int file_to_fuzz;
|
||||
int tmp_stdout, tmp_stdin;
|
||||
fpos_t pos_stdout;
|
||||
bool use_stdin = false;
|
||||
|
||||
share__opterr = 0;
|
||||
share__optind = 0;
|
||||
|
||||
|
||||
if(size < 2)
|
||||
return 0;
|
||||
|
||||
maxarg = data[0] & 15;
|
||||
use_stdin = data[0] & 16;
|
||||
size_left--;
|
||||
|
||||
argv[0] = exename;
|
||||
numarg++;
|
||||
|
||||
/* Check whether input is zero delimited */
|
||||
while((arglen = strnlen((char *)data+(size-size_left),size_left)) < size_left && numarg < maxarg) {
|
||||
argv[numarg++] = (char *)data+(size-size_left);
|
||||
size_left -= arglen + 1;
|
||||
}
|
||||
|
||||
/* Create file to feed directly */
|
||||
file_to_fuzz = mkstemp(filename);
|
||||
if (file_to_fuzz < 0)
|
||||
abort();
|
||||
if(use_stdin) {
|
||||
write(file_to_fuzz,data+(size-size_left),size_left/2);
|
||||
size_left -= size_left/2;
|
||||
}
|
||||
else
|
||||
write(file_to_fuzz,data+(size-size_left),size_left);
|
||||
close(file_to_fuzz);
|
||||
|
||||
argv[numarg++] = filename;
|
||||
|
||||
/* Create file to feed to stdin */
|
||||
if(use_stdin) {
|
||||
file_to_fuzz = mkstemp(filename_stdin);
|
||||
if (file_to_fuzz < 0)
|
||||
abort();
|
||||
write(file_to_fuzz,data+(size-size_left),size_left);
|
||||
close(file_to_fuzz);
|
||||
}
|
||||
|
||||
/* redirect stdout */
|
||||
fflush(stdout);
|
||||
fgetpos(stdout,&pos_stdout);
|
||||
tmp_stdout = dup(fileno(stdout));
|
||||
freopen("/dev/null","w",stdout);
|
||||
|
||||
/* redirect stdin */
|
||||
tmp_stdin = dup(fileno(stdin));
|
||||
if(use_stdin)
|
||||
freopen(filename_stdin,"r",stdin);
|
||||
else {
|
||||
freopen("/dev/null","r",stdin);
|
||||
argv[numarg++] = filename;
|
||||
}
|
||||
|
||||
main_to_fuzz(numarg,argv);
|
||||
|
||||
/* restore stdout */
|
||||
fflush(stdout);
|
||||
dup2(tmp_stdout, fileno(stdout));
|
||||
close(tmp_stdout);
|
||||
clearerr(stdout);
|
||||
fsetpos(stdout,&pos_stdout);
|
||||
|
||||
/* restore stdin */
|
||||
dup2(tmp_stdin, fileno(stdin));
|
||||
close(tmp_stdin);
|
||||
clearerr(stdin);
|
||||
|
||||
unlink(filename);
|
||||
|
||||
if(use_stdin)
|
||||
unlink(filename_stdin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user