mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 09:46:52 -05:00
fuzz: Avoid timeout and bloat in fuzz targets
Also, fix iwyu
This commit is contained in:
parent
82ea4e787c
commit
fabb5046a7
5 changed files with 60 additions and 28 deletions
|
@ -10,21 +10,22 @@
|
|||
#include <uint256.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
FUZZ_TARGET(bloom_filter)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
bool good_data{true};
|
||||
|
||||
CBloomFilter bloom_filter{
|
||||
fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 10000000),
|
||||
1.0 / fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, std::numeric_limits<unsigned int>::max()),
|
||||
fuzzed_data_provider.ConsumeIntegral<unsigned int>(),
|
||||
static_cast<unsigned char>(fuzzed_data_provider.PickValueInArray({BLOOM_UPDATE_NONE, BLOOM_UPDATE_ALL, BLOOM_UPDATE_P2PUBKEY_ONLY, BLOOM_UPDATE_MASK}))};
|
||||
LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 10000) {
|
||||
LIMITED_WHILE(good_data && fuzzed_data_provider.remaining_bytes() > 0, 10'000)
|
||||
{
|
||||
CallOneOf(
|
||||
fuzzed_data_provider,
|
||||
[&] {
|
||||
|
@ -37,6 +38,7 @@ FUZZ_TARGET(bloom_filter)
|
|||
[&] {
|
||||
const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
|
||||
if (!out_point) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
(void)bloom_filter.contains(*out_point);
|
||||
|
@ -47,6 +49,7 @@ FUZZ_TARGET(bloom_filter)
|
|||
[&] {
|
||||
const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
|
||||
if (!u256) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
(void)bloom_filter.contains(*u256);
|
||||
|
@ -57,6 +60,7 @@ FUZZ_TARGET(bloom_filter)
|
|||
[&] {
|
||||
const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
|
||||
if (!mut_tx) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
const CTransaction tx{*mut_tx};
|
||||
|
|
|
@ -2,26 +2,28 @@
|
|||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <coins.h>
|
||||
#include <consensus/amount.h>
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <key.h>
|
||||
#include <policy/policy.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <pubkey.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <validation.h>
|
||||
#include <util/hasher.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
@ -44,12 +46,15 @@ void initialize_coins_view()
|
|||
FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
bool good_data{true};
|
||||
|
||||
CCoinsView backend_coins_view;
|
||||
CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true};
|
||||
COutPoint random_out_point;
|
||||
Coin random_coin;
|
||||
CMutableTransaction random_mutable_transaction;
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
|
||||
LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10'000)
|
||||
{
|
||||
CallOneOf(
|
||||
fuzzed_data_provider,
|
||||
[&] {
|
||||
|
@ -95,6 +100,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
|||
[&] {
|
||||
const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
|
||||
if (!opt_out_point) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
random_out_point = *opt_out_point;
|
||||
|
@ -102,6 +108,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
|||
[&] {
|
||||
const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
|
||||
if (!opt_coin) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
random_coin = *opt_coin;
|
||||
|
@ -109,6 +116,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
|||
[&] {
|
||||
const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
|
||||
if (!opt_mutable_transaction) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
random_mutable_transaction = *opt_mutable_transaction;
|
||||
|
@ -116,7 +124,8 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
|||
[&] {
|
||||
CCoinsMapMemoryResource resource;
|
||||
CCoinsMap coins_map{0, SaltedOutpointHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource};
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
|
||||
LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10'000)
|
||||
{
|
||||
CCoinsCacheEntry coins_cache_entry;
|
||||
coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>();
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
|
@ -124,6 +133,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
|||
} else {
|
||||
const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
|
||||
if (!opt_coin) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
coins_cache_entry.coin = *opt_coin;
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
/**
|
||||
* Can be used to limit a theoretically unbounded loop. This caps the runtime
|
||||
* to avoid timeouts or OOMs.
|
||||
*
|
||||
* This can be used in combination with a check in the condition to confirm
|
||||
* whether the fuzz engine provided "good" data. If the fuzz input contains
|
||||
* invalid data, the loop aborts early. This will teach the fuzz engine to look
|
||||
* for useful data and avoids bloating the fuzz input folder with useless data.
|
||||
*/
|
||||
#define LIMITED_WHILE(condition, limit) \
|
||||
for (unsigned _count{limit}; (condition) && _count; --_count)
|
||||
|
|
|
@ -6,16 +6,14 @@
|
|||
#include <policy/fees.h>
|
||||
#include <policy/fees_args.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <streams.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
#include <test/fuzz/util/mempool.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
@ -31,13 +29,17 @@ void initialize_policy_estimator()
|
|||
FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
bool good_data{true};
|
||||
|
||||
CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES};
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
|
||||
LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10'000)
|
||||
{
|
||||
CallOneOf(
|
||||
fuzzed_data_provider,
|
||||
[&] {
|
||||
const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
|
||||
if (!mtx) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
const CTransaction tx{*mtx};
|
||||
|
@ -48,9 +50,11 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
|
|||
},
|
||||
[&] {
|
||||
std::vector<CTxMemPoolEntry> mempool_entries;
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
|
||||
{
|
||||
const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
|
||||
if (!mtx) {
|
||||
good_data = false;
|
||||
break;
|
||||
}
|
||||
const CTransaction tx{*mtx};
|
||||
|
|
|
@ -3,18 +3,14 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <base58.h>
|
||||
#include <core_io.h>
|
||||
#include <key.h>
|
||||
#include <key_io.h>
|
||||
#include <node/context.h>
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <psbt.h>
|
||||
#include <rpc/blockchain.h>
|
||||
#include <rpc/client.h>
|
||||
#include <rpc/request.h>
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/util.h>
|
||||
#include <span.h>
|
||||
#include <streams.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
|
@ -22,19 +18,23 @@
|
|||
#include <test/fuzz/util.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <tinyformat.h>
|
||||
#include <uint256.h>
|
||||
#include <univalue.h>
|
||||
#include <util/chaintype.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
#include <util/time.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
enum class ChainType;
|
||||
|
||||
namespace {
|
||||
struct RPCFuzzTestingSetup : public TestingSetup {
|
||||
|
@ -184,7 +184,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
|
|||
"waitfornewblock",
|
||||
};
|
||||
|
||||
std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
||||
std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider, bool& good_data)
|
||||
{
|
||||
const size_t max_string_length = 4096;
|
||||
const size_t max_base58_bytes_length{64};
|
||||
|
@ -251,6 +251,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
// hex encoded block
|
||||
std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
|
||||
if (!opt_block) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION};
|
||||
|
@ -261,6 +262,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
// hex encoded block header
|
||||
std::optional<CBlockHeader> opt_block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider);
|
||||
if (!opt_block_header) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
DataStream data_stream{};
|
||||
|
@ -271,6 +273,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
// hex encoded tx
|
||||
std::optional<CMutableTransaction> opt_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
|
||||
if (!opt_tx) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
CDataStream data_stream{SER_NETWORK, fuzzed_data_provider.ConsumeBool() ? PROTOCOL_VERSION : (PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)};
|
||||
|
@ -281,6 +284,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
// base64 encoded psbt
|
||||
std::optional<PartiallySignedTransaction> opt_psbt = ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider);
|
||||
if (!opt_psbt) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION};
|
||||
|
@ -291,6 +295,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
// base58 encoded key
|
||||
CKey key = ConsumePrivateKey(fuzzed_data_provider);
|
||||
if (!key.IsValid()) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
r = EncodeSecret(key);
|
||||
|
@ -299,6 +304,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
// hex encoded pubkey
|
||||
CKey key = ConsumePrivateKey(fuzzed_data_provider);
|
||||
if (!key.IsValid()) {
|
||||
good_data = false;
|
||||
return;
|
||||
}
|
||||
r = HexStr(key.GetPubKey());
|
||||
|
@ -306,18 +312,19 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
|||
return r;
|
||||
}
|
||||
|
||||
std::string ConsumeArrayRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
||||
std::string ConsumeArrayRPCArgument(FuzzedDataProvider& fuzzed_data_provider, bool& good_data)
|
||||
{
|
||||
std::vector<std::string> scalar_arguments;
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) {
|
||||
scalar_arguments.push_back(ConsumeScalarRPCArgument(fuzzed_data_provider));
|
||||
LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 100)
|
||||
{
|
||||
scalar_arguments.push_back(ConsumeScalarRPCArgument(fuzzed_data_provider, good_data));
|
||||
}
|
||||
return "[\"" + Join(scalar_arguments, "\",\"") + "\"]";
|
||||
}
|
||||
|
||||
std::string ConsumeRPCArgument(FuzzedDataProvider& fuzzed_data_provider)
|
||||
std::string ConsumeRPCArgument(FuzzedDataProvider& fuzzed_data_provider, bool& good_data)
|
||||
{
|
||||
return fuzzed_data_provider.ConsumeBool() ? ConsumeScalarRPCArgument(fuzzed_data_provider) : ConsumeArrayRPCArgument(fuzzed_data_provider);
|
||||
return fuzzed_data_provider.ConsumeBool() ? ConsumeScalarRPCArgument(fuzzed_data_provider, good_data) : ConsumeArrayRPCArgument(fuzzed_data_provider, good_data);
|
||||
}
|
||||
|
||||
RPCFuzzTestingSetup* InitializeRPCFuzzTestingSetup()
|
||||
|
@ -353,6 +360,7 @@ void initialize_rpc()
|
|||
FUZZ_TARGET(rpc, .init = initialize_rpc)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
bool good_data{true};
|
||||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
const std::string rpc_command = fuzzed_data_provider.ConsumeRandomLengthString(64);
|
||||
if (!g_limit_to_rpc_command.empty() && rpc_command != g_limit_to_rpc_command) {
|
||||
|
@ -363,8 +371,9 @@ FUZZ_TARGET(rpc, .init = initialize_rpc)
|
|||
return;
|
||||
}
|
||||
std::vector<std::string> arguments;
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) {
|
||||
arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider));
|
||||
LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 100)
|
||||
{
|
||||
arguments.push_back(ConsumeRPCArgument(fuzzed_data_provider, good_data));
|
||||
}
|
||||
try {
|
||||
rpc_testing_setup->CallRPC(rpc_command, arguments);
|
||||
|
|
Loading…
Add table
Reference in a new issue