2020-04-16 13:14:08 -04:00
|
|
|
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
2020-02-24 20:35:10 +00:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#ifndef BITCOIN_TEST_FUZZ_UTIL_H
|
|
|
|
#define BITCOIN_TEST_FUZZ_UTIL_H
|
|
|
|
|
2020-03-15 02:24:38 +00:00
|
|
|
#include <amount.h>
|
2020-03-22 14:16:40 +00:00
|
|
|
#include <arith_uint256.h>
|
2020-02-24 20:35:10 +00:00
|
|
|
#include <attributes.h>
|
2020-06-09 11:16:13 +00:00
|
|
|
#include <chainparamsbase.h>
|
2020-04-28 12:27:56 +00:00
|
|
|
#include <coins.h>
|
2020-04-26 19:27:54 +00:00
|
|
|
#include <consensus/consensus.h>
|
2020-05-24 18:11:55 +00:00
|
|
|
#include <merkleblock.h>
|
2020-10-18 16:20:04 +00:00
|
|
|
#include <net.h>
|
2020-06-09 09:45:39 +00:00
|
|
|
#include <netaddress.h>
|
2020-06-09 11:16:13 +00:00
|
|
|
#include <netbase.h>
|
2020-04-26 19:27:54 +00:00
|
|
|
#include <primitives/transaction.h>
|
2020-02-19 16:42:42 +00:00
|
|
|
#include <script/script.h>
|
2020-05-16 18:13:36 +00:00
|
|
|
#include <script/standard.h>
|
2020-02-24 20:35:10 +00:00
|
|
|
#include <serialize.h>
|
|
|
|
#include <streams.h>
|
|
|
|
#include <test/fuzz/FuzzedDataProvider.h>
|
2020-02-19 16:42:42 +00:00
|
|
|
#include <test/fuzz/fuzz.h>
|
2020-12-28 21:31:33 +01:00
|
|
|
#include <test/util/net.h>
|
2020-06-09 11:16:13 +00:00
|
|
|
#include <test/util/setup_common.h>
|
2020-04-26 19:27:54 +00:00
|
|
|
#include <txmempool.h>
|
2020-03-24 14:35:51 +00:00
|
|
|
#include <uint256.h>
|
2020-05-24 18:11:55 +00:00
|
|
|
#include <util/time.h>
|
2020-02-24 20:35:10 +00:00
|
|
|
#include <version.h>
|
|
|
|
|
2020-05-16 18:13:36 +00:00
|
|
|
#include <algorithm>
|
2020-02-24 20:35:10 +00:00
|
|
|
#include <cstdint>
|
2020-06-02 18:58:21 +00:00
|
|
|
#include <cstdio>
|
2020-05-10 18:35:55 +00:00
|
|
|
#include <optional>
|
2020-02-24 20:35:10 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2021-01-02 13:38:14 +01:00
|
|
|
template <typename... Callables>
|
|
|
|
void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
|
|
|
|
{
|
|
|
|
constexpr size_t call_size{sizeof...(callables)};
|
|
|
|
static_assert(call_size >= 1);
|
|
|
|
const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, call_size - 1)};
|
|
|
|
|
|
|
|
size_t i{0};
|
|
|
|
return ((i++ == call_index ? callables() : void()), ...);
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
2020-02-24 20:35:10 +00:00
|
|
|
{
|
|
|
|
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
|
|
|
|
return {s.begin(), s.end()};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
2020-05-24 18:11:55 +00:00
|
|
|
{
|
|
|
|
return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length));
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
2020-05-16 18:13:36 +00:00
|
|
|
{
|
|
|
|
return {ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
|
2020-03-15 14:08:34 +00:00
|
|
|
{
|
|
|
|
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
|
|
|
|
std::vector<std::string> r;
|
|
|
|
for (size_t i = 0; i < n_elements; ++i) {
|
|
|
|
r.push_back(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-02-24 20:35:10 +00:00
|
|
|
template <typename T>
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept
|
2020-03-28 08:56:38 +00:00
|
|
|
{
|
|
|
|
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
|
|
|
|
std::vector<T> r;
|
|
|
|
for (size_t i = 0; i < n_elements; ++i) {
|
|
|
|
r.push_back(fuzzed_data_provider.ConsumeIntegral<T>());
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
2020-02-24 20:35:10 +00:00
|
|
|
{
|
2020-02-26 20:04:23 +00:00
|
|
|
const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
|
2020-02-24 20:35:10 +00:00
|
|
|
CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
|
|
|
|
T obj;
|
|
|
|
try {
|
|
|
|
ds >> obj;
|
|
|
|
} catch (const std::ios_base::failure&) {
|
2020-05-10 18:35:55 +00:00
|
|
|
return std::nullopt;
|
2020-02-24 20:35:10 +00:00
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2020-12-28 21:58:00 +01:00
|
|
|
template <typename WeakEnumType, size_t size>
|
|
|
|
[[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
|
|
|
|
{
|
|
|
|
return fuzzed_data_provider.ConsumeBool() ?
|
|
|
|
fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) :
|
|
|
|
WeakEnumType(fuzzed_data_provider.ConsumeIntegral<typename std::underlying_type<WeakEnumType>::type>());
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-02-19 16:42:42 +00:00
|
|
|
{
|
|
|
|
return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-03-15 02:24:38 +00:00
|
|
|
{
|
|
|
|
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY);
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-05-24 18:11:55 +00:00
|
|
|
{
|
2020-11-19 10:43:00 +00:00
|
|
|
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) is a no-op.
|
|
|
|
static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
|
2020-05-24 18:11:55 +00:00
|
|
|
static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
|
|
|
|
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-02-19 16:42:42 +00:00
|
|
|
{
|
|
|
|
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
|
|
|
|
return {b.begin(), b.end()};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-02-19 16:42:42 +00:00
|
|
|
{
|
|
|
|
return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-05-16 18:13:36 +00:00
|
|
|
{
|
|
|
|
const std::vector<uint8_t> v160 = fuzzed_data_provider.ConsumeBytes<uint8_t>(160 / 8);
|
|
|
|
if (v160.size() != 160 / 8) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
return uint160{v160};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-03-24 14:35:51 +00:00
|
|
|
{
|
2020-05-16 18:13:36 +00:00
|
|
|
const std::vector<uint8_t> v256 = fuzzed_data_provider.ConsumeBytes<uint8_t>(256 / 8);
|
|
|
|
if (v256.size() != 256 / 8) {
|
2020-03-24 14:35:51 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
return uint256{v256};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-03-22 14:16:40 +00:00
|
|
|
{
|
|
|
|
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
|
2020-04-26 19:27:54 +00:00
|
|
|
{
|
|
|
|
// Avoid:
|
|
|
|
// policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
|
2020-04-30 14:19:27 +00:00
|
|
|
//
|
|
|
|
// Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
|
|
|
|
const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000));
|
|
|
|
assert(MoneyRange(fee));
|
2020-04-26 19:27:54 +00:00
|
|
|
const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>();
|
|
|
|
const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
|
|
|
|
const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
|
|
|
|
const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST);
|
|
|
|
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-05-16 18:13:36 +00:00
|
|
|
{
|
|
|
|
CTxDestination tx_destination;
|
2021-01-02 13:38:14 +01:00
|
|
|
CallOneOf(
|
|
|
|
fuzzed_data_provider,
|
|
|
|
[&] {
|
|
|
|
tx_destination = CNoDestination{};
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
WitnessUnknown witness_unknown{};
|
|
|
|
witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<int>();
|
|
|
|
const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
|
|
|
|
witness_unknown.length = witness_unknown_program_1.size();
|
|
|
|
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
|
|
|
|
tx_destination = witness_unknown;
|
|
|
|
});
|
2020-05-16 18:13:36 +00:00
|
|
|
return tx_destination;
|
|
|
|
}
|
|
|
|
|
2020-03-15 02:24:38 +00:00
|
|
|
template <typename T>
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] bool MultiplicationOverflow(const T i, const T j) noexcept
|
2020-03-15 02:24:38 +00:00
|
|
|
{
|
|
|
|
static_assert(std::is_integral<T>::value, "Integral required.");
|
|
|
|
if (std::numeric_limits<T>::is_signed) {
|
|
|
|
if (i > 0) {
|
|
|
|
if (j > 0) {
|
|
|
|
return i > (std::numeric_limits<T>::max() / j);
|
|
|
|
} else {
|
|
|
|
return j < (std::numeric_limits<T>::min() / i);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (j > 0) {
|
|
|
|
return i < (std::numeric_limits<T>::min() / j);
|
|
|
|
} else {
|
|
|
|
return i != 0 && (j < (std::numeric_limits<T>::max() / i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return j != 0 && i > std::numeric_limits<T>::max() / j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 16:31:43 +00:00
|
|
|
template <class T>
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
|
2020-04-07 16:31:43 +00:00
|
|
|
{
|
|
|
|
static_assert(std::is_integral<T>::value, "Integral required.");
|
|
|
|
if (std::numeric_limits<T>::is_signed) {
|
|
|
|
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
|
|
|
|
(i < 0 && j < std::numeric_limits<T>::min() - i);
|
|
|
|
}
|
|
|
|
return std::numeric_limits<T>::max() - i < j;
|
|
|
|
}
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
|
2020-04-28 12:27:56 +00:00
|
|
|
{
|
|
|
|
for (const CTxIn& tx_in : tx.vin) {
|
|
|
|
const Coin& coin = inputs.AccessCoin(tx_in.prevout);
|
|
|
|
if (coin.IsSpent()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-11 12:41:39 +00:00
|
|
|
/**
|
|
|
|
* Returns a byte vector of specified size regardless of the number of remaining bytes available
|
|
|
|
* from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
|
|
|
|
*/
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept
|
2020-06-11 12:41:39 +00:00
|
|
|
{
|
|
|
|
std::vector<uint8_t> result(length);
|
|
|
|
const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(length);
|
|
|
|
if (!random_bytes.empty()) {
|
|
|
|
std::memcpy(result.data(), random_bytes.data(), random_bytes.size());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-12-20 18:19:43 -05:00
|
|
|
inline CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-06-09 09:45:39 +00:00
|
|
|
{
|
|
|
|
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
|
|
|
|
CNetAddr net_addr;
|
|
|
|
if (network == Network::NET_IPV4) {
|
|
|
|
const in_addr v4_addr = {
|
|
|
|
.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
|
|
|
net_addr = CNetAddr{v4_addr};
|
|
|
|
} else if (network == Network::NET_IPV6) {
|
|
|
|
if (fuzzed_data_provider.remaining_bytes() >= 16) {
|
|
|
|
in6_addr v6_addr = {};
|
|
|
|
memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
|
|
|
|
net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
|
|
|
}
|
|
|
|
} else if (network == Network::NET_INTERNAL) {
|
|
|
|
net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
|
|
|
|
} else if (network == Network::NET_ONION) {
|
|
|
|
net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
|
|
|
|
}
|
|
|
|
return net_addr;
|
|
|
|
}
|
|
|
|
|
2020-12-20 18:19:43 -05:00
|
|
|
inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-06-09 09:45:39 +00:00
|
|
|
{
|
2020-08-24 21:34:26 +02:00
|
|
|
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
|
2020-06-09 09:45:39 +00:00
|
|
|
}
|
|
|
|
|
2020-12-20 18:19:43 -05:00
|
|
|
inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-10-18 16:20:04 +00:00
|
|
|
{
|
|
|
|
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
|
|
|
|
}
|
|
|
|
|
2020-12-20 18:19:43 -05:00
|
|
|
inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-10-18 16:20:04 +00:00
|
|
|
{
|
2021-01-02 10:14:39 +01:00
|
|
|
return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
|
2020-10-18 16:20:04 +00:00
|
|
|
}
|
|
|
|
|
2020-12-28 21:53:19 +01:00
|
|
|
template <bool ReturnUniquePtr = false>
|
2021-01-07 19:13:57 +01:00
|
|
|
auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
|
2020-10-18 16:20:04 +00:00
|
|
|
{
|
2020-12-28 21:53:19 +01:00
|
|
|
const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegral<NodeId>());
|
2021-01-02 10:14:39 +01:00
|
|
|
const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
|
2020-10-18 16:20:04 +00:00
|
|
|
const SOCKET socket = INVALID_SOCKET;
|
|
|
|
const CAddress address = ConsumeAddress(fuzzed_data_provider);
|
|
|
|
const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
|
|
|
|
const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
|
|
|
|
const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
|
|
|
|
const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
|
2020-12-28 21:31:33 +01:00
|
|
|
const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
|
2020-12-17 16:33:56 +01:00
|
|
|
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
|
2020-12-28 21:53:19 +01:00
|
|
|
if constexpr (ReturnUniquePtr) {
|
|
|
|
return std::make_unique<CNode>(node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion);
|
|
|
|
} else {
|
|
|
|
return CNode{node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion};
|
|
|
|
}
|
2020-10-18 16:20:04 +00:00
|
|
|
}
|
2020-12-28 21:53:19 +01:00
|
|
|
inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
|
2020-10-18 16:20:04 +00:00
|
|
|
|
2021-01-07 19:13:57 +01:00
|
|
|
inline void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, const std::optional<int32_t>& version_in = std::nullopt) noexcept
|
|
|
|
{
|
|
|
|
const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
|
|
|
|
const NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
|
|
|
|
const int32_t version = version_in.value_or(fuzzed_data_provider.ConsumeIntegral<int32_t>());
|
|
|
|
const bool filter_txs = fuzzed_data_provider.ConsumeBool();
|
|
|
|
|
|
|
|
node.nServices = remote_services;
|
|
|
|
node.m_permissionFlags = permission_flags;
|
|
|
|
node.nVersion = version;
|
|
|
|
node.SetCommonVersion(version);
|
|
|
|
if (node.m_tx_relay != nullptr) {
|
|
|
|
LOCK(node.m_tx_relay->cs_filter);
|
|
|
|
node.m_tx_relay->fRelayTxes = filter_txs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-20 18:19:43 -05:00
|
|
|
inline void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
|
2020-06-09 11:16:13 +00:00
|
|
|
{
|
|
|
|
static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
|
|
|
|
}
|
|
|
|
|
2020-06-02 18:58:21 +00:00
|
|
|
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;
|
2021-01-02 13:38:14 +01:00
|
|
|
CallOneOf(
|
|
|
|
m_fuzzed_data_provider,
|
|
|
|
[&] {
|
|
|
|
mode = "r";
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
mode = "r+";
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
mode = "w";
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
mode = "w+";
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
mode = "a";
|
|
|
|
},
|
|
|
|
[&] {
|
|
|
|
mode = "a+";
|
|
|
|
});
|
2020-06-02 18:58:21 +00:00
|
|
|
#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());
|
2020-07-21 15:21:27 -07:00
|
|
|
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)random_bytes.size())) {
|
2020-06-02 18:58:21 +00:00
|
|
|
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);
|
2020-07-21 15:21:27 -07:00
|
|
|
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
|
2020-06-02 18:58:21 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-06-02 18:58:21 +00:00
|
|
|
{
|
|
|
|
return {fuzzed_data_provider};
|
|
|
|
}
|
|
|
|
|
2020-06-02 19:02:26 +00:00
|
|
|
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>()};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-26 09:05:59 +00:00
|
|
|
[[nodiscard]] inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
2020-06-02 19:02:26 +00:00
|
|
|
{
|
|
|
|
return {fuzzed_data_provider};
|
|
|
|
}
|
|
|
|
|
2021-01-02 13:38:14 +01:00
|
|
|
#define WRITE_TO_STREAM_CASE(type, consume) \
|
|
|
|
[&] { \
|
|
|
|
type o = consume; \
|
|
|
|
stream << o; \
|
2020-06-02 19:03:52 +00:00
|
|
|
}
|
|
|
|
template <typename Stream>
|
|
|
|
void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
|
|
|
|
{
|
|
|
|
while (fuzzed_data_provider.ConsumeBool()) {
|
|
|
|
try {
|
2021-01-02 13:38:14 +01:00
|
|
|
CallOneOf(
|
|
|
|
fuzzed_data_provider,
|
|
|
|
WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()),
|
|
|
|
WRITE_TO_STREAM_CASE(char, fuzzed_data_provider.ConsumeIntegral<char>()),
|
|
|
|
WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
|
|
|
|
WRITE_TO_STREAM_CASE(float, fuzzed_data_provider.ConsumeFloatingPoint<float>()),
|
|
|
|
WRITE_TO_STREAM_CASE(double, fuzzed_data_provider.ConsumeFloatingPoint<double>()),
|
|
|
|
WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)),
|
|
|
|
WRITE_TO_STREAM_CASE(std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider)));
|
2020-06-02 19:03:52 +00:00
|
|
|
} catch (const std::ios_base::failure&) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 13:38:14 +01:00
|
|
|
#define READ_FROM_STREAM_CASE(type) \
|
|
|
|
[&] { \
|
|
|
|
type o; \
|
|
|
|
stream >> o; \
|
2020-06-02 19:03:52 +00:00
|
|
|
}
|
|
|
|
template <typename Stream>
|
|
|
|
void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
|
|
|
|
{
|
|
|
|
while (fuzzed_data_provider.ConsumeBool()) {
|
|
|
|
try {
|
2021-01-02 13:38:14 +01:00
|
|
|
CallOneOf(
|
|
|
|
fuzzed_data_provider,
|
|
|
|
READ_FROM_STREAM_CASE(bool),
|
|
|
|
READ_FROM_STREAM_CASE(char),
|
|
|
|
READ_FROM_STREAM_CASE(int8_t),
|
|
|
|
READ_FROM_STREAM_CASE(uint8_t),
|
|
|
|
READ_FROM_STREAM_CASE(int16_t),
|
|
|
|
READ_FROM_STREAM_CASE(uint16_t),
|
|
|
|
READ_FROM_STREAM_CASE(int32_t),
|
|
|
|
READ_FROM_STREAM_CASE(uint32_t),
|
|
|
|
READ_FROM_STREAM_CASE(int64_t),
|
|
|
|
READ_FROM_STREAM_CASE(uint64_t),
|
|
|
|
READ_FROM_STREAM_CASE(float),
|
|
|
|
READ_FROM_STREAM_CASE(double),
|
|
|
|
READ_FROM_STREAM_CASE(std::string),
|
|
|
|
READ_FROM_STREAM_CASE(std::vector<char>));
|
2020-06-02 19:03:52 +00:00
|
|
|
} catch (const std::ios_base::failure&) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 20:35:10 +00:00
|
|
|
#endif // BITCOIN_TEST_FUZZ_UTIL_H
|