mirror of
https://github.com/claunia/flac.git
synced 2025-12-16 18:54:26 +00:00
oss-fuzz: Add fuzzing headers
These includes header files were taken from:
https://github.com/guidovranken/fuzzing-headers.git
with some minor changes required to make them compile cleanly
with the extra compiler warning flags used by the FLAC build
system.
This commit is contained in:
6
oss-fuzz/fuzzing/Readme.md
Normal file
6
oss-fuzz/fuzzing/Readme.md
Normal file
@@ -0,0 +1,6 @@
|
||||
The header files in this directory 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.
|
||||
167
oss-fuzz/fuzzing/datasource/datasource.hpp
Normal file
167
oss-fuzz/fuzzing/datasource/datasource.hpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#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 opertator 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 */
|
||||
52
oss-fuzz/fuzzing/datasource/id.hpp
Normal file
52
oss-fuzz/fuzzing/datasource/id.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#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 */
|
||||
44
oss-fuzz/fuzzing/exception.hpp
Normal file
44
oss-fuzz/fuzzing/exception.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#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 */
|
||||
73
oss-fuzz/fuzzing/memory.hpp
Normal file
73
oss-fuzz/fuzzing/memory.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#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 */
|
||||
135
oss-fuzz/fuzzing/types.hpp
Normal file
135
oss-fuzz/fuzzing/types.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#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 */
|
||||
Reference in New Issue
Block a user