Changeset View
Changeset View
Standalone View
Standalone View
src/test/fuzz/util.h
Show All 18 Lines | |||||
#include <version.h> | #include <version.h> | ||||
#include <test/fuzz/FuzzedDataProvider.h> | #include <test/fuzz/FuzzedDataProvider.h> | ||||
#include <test/fuzz/fuzz.h> | #include <test/fuzz/fuzz.h> | ||||
#include <test/util/setup_common.h> | #include <test/util/setup_common.h> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include <cstdint> | #include <cstdint> | ||||
#include <cstdio> | |||||
#include <string> | #include <string> | ||||
#include <vector> | #include <vector> | ||||
namespace fuzzer { | namespace fuzzer { | ||||
// FIXME find a better way to avoid duplicating the MAX_MONEY definition | // FIXME find a better way to avoid duplicating the MAX_MONEY definition | ||||
constexpr int64_t MAX_MONEY_AS_INT = int64_t(21000000) * int64_t(100000000); | constexpr int64_t MAX_MONEY_AS_INT = int64_t(21000000) * int64_t(100000000); | ||||
} // end namespace fuzzer | } // end namespace fuzzer | ||||
▲ Show 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void InitializeFuzzingContext( | void InitializeFuzzingContext( | ||||
const std::string &chain_name = CBaseChainParams::REGTEST) { | const std::string &chain_name = CBaseChainParams::REGTEST) { | ||||
static const BasicTestingSetup basic_testing_setup{chain_name, | static const BasicTestingSetup basic_testing_setup{chain_name, | ||||
{"-nodebuglogfile"}}; | {"-nodebuglogfile"}}; | ||||
} | } | ||||
class FuzzedFileProvider { | |||||
FuzzedDataProvider &m_fuzzed_data_provider; | |||||
int64_t m_offset = 0; | |||||
public: | |||||
FuzzedFileProvider(FuzzedDataProvider &fuzzed_data_provider) | |||||
: m_fuzzed_data_provider{fuzzed_data_provider} {} | |||||
FILE *open() { | |||||
if (m_fuzzed_data_provider.ConsumeBool()) { | |||||
return nullptr; | |||||
} | |||||
std::string mode; | |||||
switch (m_fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) { | |||||
case 0: { | |||||
mode = "r"; | |||||
break; | |||||
} | |||||
case 1: { | |||||
mode = "r+"; | |||||
break; | |||||
} | |||||
case 2: { | |||||
mode = "w"; | |||||
break; | |||||
} | |||||
case 3: { | |||||
mode = "w+"; | |||||
break; | |||||
} | |||||
case 4: { | |||||
mode = "a"; | |||||
break; | |||||
} | |||||
case 5: { | |||||
mode = "a+"; | |||||
break; | |||||
} | |||||
} | |||||
#ifdef _GNU_SOURCE | |||||
const cookie_io_functions_t io_hooks = { | |||||
FuzzedFileProvider::read, | |||||
FuzzedFileProvider::write, | |||||
FuzzedFileProvider::seek, | |||||
FuzzedFileProvider::close, | |||||
}; | |||||
return fopencookie(this, mode.c_str(), io_hooks); | |||||
#else | |||||
(void)mode; | |||||
return nullptr; | |||||
#endif | |||||
} | |||||
static ssize_t read(void *cookie, char *buf, size_t size) { | |||||
FuzzedFileProvider *fuzzed_file = (FuzzedFileProvider *)cookie; | |||||
if (buf == nullptr || size == 0 || | |||||
fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) { | |||||
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; | |||||
} | |||||
const std::vector<uint8_t> random_bytes = | |||||
fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size); | |||||
if (random_bytes.empty()) { | |||||
return 0; | |||||
} | |||||
std::memcpy(buf, random_bytes.data(), random_bytes.size()); | |||||
if (AdditionOverflow((uint64_t)fuzzed_file->m_offset, | |||||
random_bytes.size())) { | |||||
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; | |||||
} | |||||
fuzzed_file->m_offset += random_bytes.size(); | |||||
return random_bytes.size(); | |||||
} | |||||
static ssize_t write(void *cookie, const char *buf, size_t size) { | |||||
FuzzedFileProvider *fuzzed_file = (FuzzedFileProvider *)cookie; | |||||
const ssize_t n = | |||||
fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>( | |||||
0, size); | |||||
if (AdditionOverflow(fuzzed_file->m_offset, n)) { | |||||
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; | |||||
} | |||||
fuzzed_file->m_offset += n; | |||||
return n; | |||||
} | |||||
static int seek(void *cookie, int64_t *offset, int whence) { | |||||
// SEEK_END not implemented yet. | |||||
assert(whence == SEEK_SET || whence == SEEK_CUR); | |||||
FuzzedFileProvider *fuzzed_file = (FuzzedFileProvider *)cookie; | |||||
int64_t new_offset = 0; | |||||
if (whence == SEEK_SET) { | |||||
new_offset = *offset; | |||||
} else if (whence == SEEK_CUR) { | |||||
if (AdditionOverflow(fuzzed_file->m_offset, *offset)) { | |||||
return -1; | |||||
} | |||||
new_offset = fuzzed_file->m_offset + *offset; | |||||
} | |||||
if (new_offset < 0) { | |||||
return -1; | |||||
} | |||||
fuzzed_file->m_offset = new_offset; | |||||
*offset = new_offset; | |||||
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>( | |||||
-1, 0); | |||||
} | |||||
static int close(void *cookie) { | |||||
FuzzedFileProvider *fuzzed_file = (FuzzedFileProvider *)cookie; | |||||
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>( | |||||
-1, 0); | |||||
} | |||||
}; | |||||
NODISCARD inline FuzzedFileProvider | |||||
ConsumeFile(FuzzedDataProvider &fuzzed_data_provider) noexcept { | |||||
return {fuzzed_data_provider}; | |||||
} | |||||
class FuzzedAutoFileProvider { | |||||
FuzzedDataProvider &m_fuzzed_data_provider; | |||||
FuzzedFileProvider m_fuzzed_file_provider; | |||||
public: | |||||
FuzzedAutoFileProvider(FuzzedDataProvider &fuzzed_data_provider) | |||||
: m_fuzzed_data_provider{fuzzed_data_provider}, | |||||
m_fuzzed_file_provider{fuzzed_data_provider} {} | |||||
CAutoFile open() { | |||||
return {m_fuzzed_file_provider.open(), | |||||
m_fuzzed_data_provider.ConsumeIntegral<int>(), | |||||
m_fuzzed_data_provider.ConsumeIntegral<int>()}; | |||||
} | |||||
}; | |||||
NODISCARD inline FuzzedAutoFileProvider | |||||
ConsumeAutoFile(FuzzedDataProvider &fuzzed_data_provider) noexcept { | |||||
return {fuzzed_data_provider}; | |||||
} | |||||
#define WRITE_TO_STREAM_CASE(id, type, consume) \ | |||||
case id: { \ | |||||
type o = consume; \ | |||||
stream << o; \ | |||||
break; \ | |||||
} | |||||
template <typename Stream> | |||||
void WriteToStream(FuzzedDataProvider &fuzzed_data_provider, | |||||
Stream &stream) noexcept { | |||||
while (fuzzed_data_provider.ConsumeBool()) { | |||||
try { | |||||
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) { | |||||
WRITE_TO_STREAM_CASE(0, bool, | |||||
fuzzed_data_provider.ConsumeBool()) | |||||
WRITE_TO_STREAM_CASE( | |||||
1, char, fuzzed_data_provider.ConsumeIntegral<char>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
2, int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
3, uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
4, int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
5, uint16_t, | |||||
fuzzed_data_provider.ConsumeIntegral<uint16_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
6, int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
7, uint32_t, | |||||
fuzzed_data_provider.ConsumeIntegral<uint32_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
8, int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
9, uint64_t, | |||||
fuzzed_data_provider.ConsumeIntegral<uint64_t>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
10, float, | |||||
fuzzed_data_provider.ConsumeFloatingPoint<float>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
11, double, | |||||
fuzzed_data_provider.ConsumeFloatingPoint<double>()) | |||||
WRITE_TO_STREAM_CASE( | |||||
12, std::string, | |||||
fuzzed_data_provider.ConsumeRandomLengthString(32)) | |||||
WRITE_TO_STREAM_CASE(13, std::vector<char>, | |||||
ConsumeRandomLengthIntegralVector<char>( | |||||
fuzzed_data_provider)) | |||||
} | |||||
} catch (const std::ios_base::failure &) { | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
#define READ_FROM_STREAM_CASE(id, type) \ | |||||
case id: { \ | |||||
type o; \ | |||||
stream >> o; \ | |||||
break; \ | |||||
} | |||||
template <typename Stream> | |||||
void ReadFromStream(FuzzedDataProvider &fuzzed_data_provider, | |||||
Stream &stream) noexcept { | |||||
while (fuzzed_data_provider.ConsumeBool()) { | |||||
try { | |||||
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) { | |||||
READ_FROM_STREAM_CASE(0, bool) | |||||
READ_FROM_STREAM_CASE(1, char) | |||||
READ_FROM_STREAM_CASE(2, int8_t) | |||||
READ_FROM_STREAM_CASE(3, uint8_t) | |||||
READ_FROM_STREAM_CASE(4, int16_t) | |||||
READ_FROM_STREAM_CASE(5, uint16_t) | |||||
READ_FROM_STREAM_CASE(6, int32_t) | |||||
READ_FROM_STREAM_CASE(7, uint32_t) | |||||
READ_FROM_STREAM_CASE(8, int64_t) | |||||
READ_FROM_STREAM_CASE(9, uint64_t) | |||||
READ_FROM_STREAM_CASE(10, float) | |||||
READ_FROM_STREAM_CASE(11, double) | |||||
READ_FROM_STREAM_CASE(12, std::string) | |||||
READ_FROM_STREAM_CASE(13, std::vector<char>) | |||||
} | |||||
} catch (const std::ios_base::failure &) { | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
#endif // BITCOIN_TEST_FUZZ_UTIL_H | #endif // BITCOIN_TEST_FUZZ_UTIL_H |