diff options
Diffstat (limited to 'src/test/fuzz')
-rw-r--r-- | src/test/fuzz/addrman.cpp | 235 | ||||
-rw-r--r-- | src/test/fuzz/banman.cpp | 4 | ||||
-rw-r--r-- | src/test/fuzz/coins_view.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/deserialize.cpp | 279 | ||||
-rw-r--r-- | src/test/fuzz/integer.cpp | 16 | ||||
-rw-r--r-- | src/test/fuzz/key_io.cpp | 11 | ||||
-rw-r--r-- | src/test/fuzz/kitchen_sink.cpp | 8 | ||||
-rw-r--r-- | src/test/fuzz/multiplication_overflow.cpp | 12 | ||||
-rw-r--r-- | src/test/fuzz/netaddress.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/prevector.cpp | 6 | ||||
-rw-r--r-- | src/test/fuzz/process_message.cpp | 12 | ||||
-rw-r--r-- | src/test/fuzz/rolling_bloom_filter.cpp | 17 | ||||
-rw-r--r-- | src/test/fuzz/script.cpp | 40 | ||||
-rw-r--r-- | src/test/fuzz/string.cpp | 3 | ||||
-rw-r--r-- | src/test/fuzz/tx_pool.cpp | 12 | ||||
-rw-r--r-- | src/test/fuzz/util.cpp | 194 | ||||
-rw-r--r-- | src/test/fuzz/util.h | 189 |
17 files changed, 620 insertions, 422 deletions
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index db0b461873..4c29a8ee53 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -12,6 +12,7 @@ #include <time.h> #include <util/asmap.h> +#include <cassert> #include <cstdint> #include <optional> #include <string> @@ -25,10 +26,200 @@ void initialize_addrman() class CAddrManDeterministic : public CAddrMan { public: - void MakeDeterministic(const uint256& random_seed) + FuzzedDataProvider& m_fuzzed_data_provider; + + explicit CAddrManDeterministic(FuzzedDataProvider& fuzzed_data_provider) + : m_fuzzed_data_provider(fuzzed_data_provider) + { + WITH_LOCK(cs, insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); + if (fuzzed_data_provider.ConsumeBool()) { + m_asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); + if (!SanityCheckASMap(m_asmap)) { + m_asmap.clear(); + } + } + } + + /** + * Generate a random address. Always returns a valid address. + */ + CNetAddr RandAddr() EXCLUSIVE_LOCKS_REQUIRED(cs) + { + CNetAddr addr; + if (m_fuzzed_data_provider.remaining_bytes() > 1 && m_fuzzed_data_provider.ConsumeBool()) { + addr = ConsumeNetAddr(m_fuzzed_data_provider); + } else { + // The networks [1..6] correspond to CNetAddr::BIP155Network (private). + static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE}, + {2, ADDR_IPV6_SIZE}, + {4, ADDR_TORV3_SIZE}, + {5, ADDR_I2P_SIZE}, + {6, ADDR_CJDNS_SIZE}}; + uint8_t net = insecure_rand.randrange(5) + 1; // [1..5] + if (net == 3) { + net = 6; + } + + CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); + + s << net; + s << insecure_rand.randbytes(net_len_map.at(net)); + + s >> addr; + } + + // Return a dummy IPv4 5.5.5.5 if we generated an invalid address. + if (!addr.IsValid()) { + in_addr v4_addr = {}; + v4_addr.s_addr = 0x05050505; + addr = CNetAddr{v4_addr}; + } + + return addr; + } + + /** + * Fill this addrman with lots of addresses from lots of sources. + */ + void Fill() { - insecure_rand = FastRandomContext{random_seed}; - Clear(); + LOCK(cs); + + // Add some of the addresses directly to the "tried" table. + + // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33% + const size_t n = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3); + + const size_t num_sources = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(10, 50); + CNetAddr prev_source; + // Use insecure_rand inside the loops instead of m_fuzzed_data_provider because when + // the latter is exhausted it just returns 0. + for (size_t i = 0; i < num_sources; ++i) { + const auto source = RandAddr(); + const size_t num_addresses = insecure_rand.randrange(500) + 1; // [1..500] + + for (size_t j = 0; j < num_addresses; ++j) { + const auto addr = CAddress{CService{RandAddr(), 8333}, NODE_NETWORK}; + const auto time_penalty = insecure_rand.randrange(100000001); +#if 1 + // 2.83 sec to fill. + if (n > 0 && mapInfo.size() % n == 0 && mapAddr.find(addr) == mapAddr.end()) { + // Add to the "tried" table (if the bucket slot is free). + const CAddrInfo dummy{addr, source}; + const int bucket = dummy.GetTriedBucket(nKey, m_asmap); + const int bucket_pos = dummy.GetBucketPosition(nKey, false, bucket); + if (vvTried[bucket][bucket_pos] == -1) { + int id; + CAddrInfo* addr_info = Create(addr, source, &id); + vvTried[bucket][bucket_pos] = id; + addr_info->fInTried = true; + ++nTried; + } + } else { + // Add to the "new" table. + Add_(addr, source, time_penalty); + } +#else + // 261.91 sec to fill. + Add_(addr, source, time_penalty); + if (n > 0 && mapInfo.size() % n == 0) { + Good_(addr, false, GetTime()); + } +#endif + // Add 10% of the addresses from more than one source. + if (insecure_rand.randrange(10) == 0 && prev_source.IsValid()) { + Add_(addr, prev_source, time_penalty); + } + } + prev_source = source; + } + } + + /** + * Compare with another AddrMan. + * This compares: + * - the values in `mapInfo` (the keys aka ids are ignored) + * - vvNew entries refer to the same addresses + * - vvTried entries refer to the same addresses + */ + bool operator==(const CAddrManDeterministic& other) + { + LOCK2(cs, other.cs); + + if (mapInfo.size() != other.mapInfo.size() || nNew != other.nNew || + nTried != other.nTried) { + return false; + } + + // Check that all values in `mapInfo` are equal to all values in `other.mapInfo`. + // Keys may be different. + + using CAddrInfoHasher = std::function<size_t(const CAddrInfo&)>; + using CAddrInfoEq = std::function<bool(const CAddrInfo&, const CAddrInfo&)>; + + CNetAddrHash netaddr_hasher; + + CAddrInfoHasher addrinfo_hasher = [&netaddr_hasher](const CAddrInfo& a) { + return netaddr_hasher(static_cast<CNetAddr>(a)) ^ netaddr_hasher(a.source) ^ + a.nLastSuccess ^ a.nAttempts ^ a.nRefCount ^ a.fInTried; + }; + + CAddrInfoEq addrinfo_eq = [](const CAddrInfo& lhs, const CAddrInfo& rhs) { + return static_cast<CNetAddr>(lhs) == static_cast<CNetAddr>(rhs) && + lhs.source == rhs.source && lhs.nLastSuccess == rhs.nLastSuccess && + lhs.nAttempts == rhs.nAttempts && lhs.nRefCount == rhs.nRefCount && + lhs.fInTried == rhs.fInTried; + }; + + using Addresses = std::unordered_set<CAddrInfo, CAddrInfoHasher, CAddrInfoEq>; + + const size_t num_addresses{mapInfo.size()}; + + Addresses addresses{num_addresses, addrinfo_hasher, addrinfo_eq}; + for (const auto& [id, addr] : mapInfo) { + addresses.insert(addr); + } + + Addresses other_addresses{num_addresses, addrinfo_hasher, addrinfo_eq}; + for (const auto& [id, addr] : other.mapInfo) { + other_addresses.insert(addr); + } + + if (addresses != other_addresses) { + return false; + } + + auto IdsReferToSameAddress = [&](int id, int other_id) EXCLUSIVE_LOCKS_REQUIRED(cs, other.cs) { + if (id == -1 && other_id == -1) { + return true; + } + if ((id == -1 && other_id != -1) || (id != -1 && other_id == -1)) { + return false; + } + return mapInfo.at(id) == other.mapInfo.at(other_id); + }; + + // Check that `vvNew` contains the same addresses as `other.vvNew`. Notice - `vvNew[i][j]` + // contains just an id and the address is to be found in `mapInfo.at(id)`. The ids + // themselves may differ between `vvNew` and `other.vvNew`. + for (size_t i = 0; i < ADDRMAN_NEW_BUCKET_COUNT; ++i) { + for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) { + if (!IdsReferToSameAddress(vvNew[i][j], other.vvNew[i][j])) { + return false; + } + } + } + + // Same for `vvTried`. + for (size_t i = 0; i < ADDRMAN_TRIED_BUCKET_COUNT; ++i) { + for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) { + if (!IdsReferToSameAddress(vvTried[i][j], other.vvTried[i][j])) { + return false; + } + } + } + + return true; } }; @@ -36,12 +227,16 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); SetMockTime(ConsumeTime(fuzzed_data_provider)); - CAddrManDeterministic addr_man; - addr_man.MakeDeterministic(ConsumeUInt256(fuzzed_data_provider)); + CAddrManDeterministic addr_man{fuzzed_data_provider}; if (fuzzed_data_provider.ConsumeBool()) { - addr_man.m_asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); - if (!SanityCheckASMap(addr_man.m_asmap)) { - addr_man.m_asmap.clear(); + const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; + CDataStream ds(serialized_data, SER_DISK, INIT_PROTO_VERSION); + const auto ser_version{fuzzed_data_provider.ConsumeIntegral<int32_t>()}; + ds.SetVersion(ser_version); + try { + ds >> addr_man; + } catch (const std::ios_base::failure&) { + addr_man.Clear(); } } while (fuzzed_data_provider.ConsumeBool()) { @@ -80,7 +275,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) [&] { const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); if (opt_service) { - addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); + addr_man.Good(*opt_service, ConsumeTime(fuzzed_data_provider)); } }, [&] { @@ -103,12 +298,30 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) }); } const CAddrMan& const_addr_man{addr_man}; - (void)/*const_*/addr_man.GetAddr( + (void)const_addr_man.GetAddr( /* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), /* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), /* network */ std::nullopt); - (void)/*const_*/addr_man.Select(fuzzed_data_provider.ConsumeBool()); + (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool()); (void)const_addr_man.size(); CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); data_stream << const_addr_man; } + +// Check that serialize followed by unserialize produces the same addrman. +FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + SetMockTime(ConsumeTime(fuzzed_data_provider)); + + CAddrManDeterministic addr_man1{fuzzed_data_provider}; + CAddrManDeterministic addr_man2{fuzzed_data_provider}; + addr_man2.m_asmap = addr_man1.m_asmap; + + CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); + + addr_man1.Fill(); + data_stream << addr_man1; + data_stream >> addr_man2; + assert(addr_man1 == addr_man2); +} diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index 182aabc79b..46a9f623ac 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -52,8 +52,7 @@ FUZZ_TARGET_INIT(banman, initialize_banman) const bool start_with_corrupted_banlist{fuzzed_data_provider.ConsumeBool()}; bool force_read_and_write_to_err{false}; if (start_with_corrupted_banlist) { - const std::string sfx{fuzzed_data_provider.ConsumeBool() ? ".dat" : ".json"}; - assert(WriteBinaryFile(banlist_file.string() + sfx, + assert(WriteBinaryFile(banlist_file.string() + ".json", fuzzed_data_provider.ConsumeRandomLengthString())); } else { force_read_and_write_to_err = fuzzed_data_provider.ConsumeBool(); @@ -112,6 +111,5 @@ FUZZ_TARGET_INIT(banman, initialize_banman) assert(banmap == banmap_read); } } - fs::remove(banlist_file.string() + ".dat"); fs::remove(banlist_file.string() + ".json"); } diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index f452696689..bbdb2c6917 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -258,7 +258,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. return; } - const int flags = fuzzed_data_provider.ConsumeIntegral<int>(); + const auto flags{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) { // Avoid: // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed. diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 721e4360d0..d5b56cb7cd 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -100,228 +100,217 @@ void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT } // namespace FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, { - BlockFilter block_filter; - DeserializeFromFuzzingInput(buffer, block_filter); + BlockFilter block_filter; + DeserializeFromFuzzingInput(buffer, block_filter); }) FUZZ_TARGET_DESERIALIZE(addr_info_deserialize, { - CAddrInfo addr_info; - DeserializeFromFuzzingInput(buffer, addr_info); + CAddrInfo addr_info; + DeserializeFromFuzzingInput(buffer, addr_info); }) FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, { - CBlockFileInfo block_file_info; - DeserializeFromFuzzingInput(buffer, block_file_info); + CBlockFileInfo block_file_info; + DeserializeFromFuzzingInput(buffer, block_file_info); }) FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, { - CBlockHeaderAndShortTxIDs block_header_and_short_txids; - DeserializeFromFuzzingInput(buffer, block_header_and_short_txids); + CBlockHeaderAndShortTxIDs block_header_and_short_txids; + DeserializeFromFuzzingInput(buffer, block_header_and_short_txids); }) FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, { - CFeeRate fee_rate; - DeserializeFromFuzzingInput(buffer, fee_rate); - AssertEqualAfterSerializeDeserialize(fee_rate); + CFeeRate fee_rate; + DeserializeFromFuzzingInput(buffer, fee_rate); + AssertEqualAfterSerializeDeserialize(fee_rate); }) FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, { - CMerkleBlock merkle_block; - DeserializeFromFuzzingInput(buffer, merkle_block); + CMerkleBlock merkle_block; + DeserializeFromFuzzingInput(buffer, merkle_block); }) FUZZ_TARGET_DESERIALIZE(out_point_deserialize, { - COutPoint out_point; - DeserializeFromFuzzingInput(buffer, out_point); - AssertEqualAfterSerializeDeserialize(out_point); + COutPoint out_point; + DeserializeFromFuzzingInput(buffer, out_point); + AssertEqualAfterSerializeDeserialize(out_point); }) FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, { - CPartialMerkleTree partial_merkle_tree; - DeserializeFromFuzzingInput(buffer, partial_merkle_tree); + CPartialMerkleTree partial_merkle_tree; + DeserializeFromFuzzingInput(buffer, partial_merkle_tree); }) FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, { - CPubKey pub_key; - DeserializeFromFuzzingInput(buffer, pub_key); - AssertEqualAfterSerializeDeserialize(pub_key); + CPubKey pub_key; + DeserializeFromFuzzingInput(buffer, pub_key); + AssertEqualAfterSerializeDeserialize(pub_key); }) FUZZ_TARGET_DESERIALIZE(script_deserialize, { - CScript script; - DeserializeFromFuzzingInput(buffer, script); -}) -FUZZ_TARGET_DESERIALIZE(sub_net_deserialize, { - CSubNet sub_net_1; - DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION); - AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION); - CSubNet sub_net_2; - DeserializeFromFuzzingInput(buffer, sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT); - AssertEqualAfterSerializeDeserialize(sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT); - CSubNet sub_net_3; - DeserializeFromFuzzingInput(buffer, sub_net_3); - AssertEqualAfterSerializeDeserialize(sub_net_3, INIT_PROTO_VERSION | ADDRV2_FORMAT); + CScript script; + DeserializeFromFuzzingInput(buffer, script); }) FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, { - CTxIn tx_in; - DeserializeFromFuzzingInput(buffer, tx_in); - AssertEqualAfterSerializeDeserialize(tx_in); + CTxIn tx_in; + DeserializeFromFuzzingInput(buffer, tx_in); + AssertEqualAfterSerializeDeserialize(tx_in); }) FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, { - FlatFilePos flat_file_pos; - DeserializeFromFuzzingInput(buffer, flat_file_pos); - AssertEqualAfterSerializeDeserialize(flat_file_pos); + FlatFilePos flat_file_pos; + DeserializeFromFuzzingInput(buffer, flat_file_pos); + AssertEqualAfterSerializeDeserialize(flat_file_pos); }) FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, { - KeyOriginInfo key_origin_info; - DeserializeFromFuzzingInput(buffer, key_origin_info); - AssertEqualAfterSerializeDeserialize(key_origin_info); + KeyOriginInfo key_origin_info; + DeserializeFromFuzzingInput(buffer, key_origin_info); + AssertEqualAfterSerializeDeserialize(key_origin_info); }) FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, { - PartiallySignedTransaction partially_signed_transaction; - DeserializeFromFuzzingInput(buffer, partially_signed_transaction); + PartiallySignedTransaction partially_signed_transaction; + DeserializeFromFuzzingInput(buffer, partially_signed_transaction); }) FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, { - PrefilledTransaction prefilled_transaction; - DeserializeFromFuzzingInput(buffer, prefilled_transaction); + PrefilledTransaction prefilled_transaction; + DeserializeFromFuzzingInput(buffer, prefilled_transaction); }) FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, { - PSBTInput psbt_input; - DeserializeFromFuzzingInput(buffer, psbt_input); + PSBTInput psbt_input; + DeserializeFromFuzzingInput(buffer, psbt_input); }) FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, { - PSBTOutput psbt_output; - DeserializeFromFuzzingInput(buffer, psbt_output); + PSBTOutput psbt_output; + DeserializeFromFuzzingInput(buffer, psbt_output); }) FUZZ_TARGET_DESERIALIZE(block_deserialize, { - CBlock block; - DeserializeFromFuzzingInput(buffer, block); + CBlock block; + DeserializeFromFuzzingInput(buffer, block); }) FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, { - CBlockLocator bl; - DeserializeFromFuzzingInput(buffer, bl); + CBlockLocator bl; + DeserializeFromFuzzingInput(buffer, bl); }) FUZZ_TARGET_DESERIALIZE(blockmerkleroot, { - CBlock block; - DeserializeFromFuzzingInput(buffer, block); - bool mutated; - BlockMerkleRoot(block, &mutated); + CBlock block; + DeserializeFromFuzzingInput(buffer, block); + bool mutated; + BlockMerkleRoot(block, &mutated); }) FUZZ_TARGET_DESERIALIZE(addrman_deserialize, { - CAddrMan am; - DeserializeFromFuzzingInput(buffer, am); + CAddrMan am; + DeserializeFromFuzzingInput(buffer, am); }) FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { - CBlockHeader bh; - DeserializeFromFuzzingInput(buffer, bh); + CBlockHeader bh; + DeserializeFromFuzzingInput(buffer, bh); }) FUZZ_TARGET_DESERIALIZE(banentry_deserialize, { - CBanEntry be; - DeserializeFromFuzzingInput(buffer, be); + CBanEntry be; + DeserializeFromFuzzingInput(buffer, be); }) FUZZ_TARGET_DESERIALIZE(txundo_deserialize, { - CTxUndo tu; - DeserializeFromFuzzingInput(buffer, tu); + CTxUndo tu; + DeserializeFromFuzzingInput(buffer, tu); }) FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, { - CBlockUndo bu; - DeserializeFromFuzzingInput(buffer, bu); + CBlockUndo bu; + DeserializeFromFuzzingInput(buffer, bu); }) FUZZ_TARGET_DESERIALIZE(coins_deserialize, { - Coin coin; - DeserializeFromFuzzingInput(buffer, coin); + Coin coin; + DeserializeFromFuzzingInput(buffer, coin); }) FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, { - CNetAddr na; - DeserializeFromFuzzingInput(buffer, na); - if (na.IsAddrV1Compatible()) { - AssertEqualAfterSerializeDeserialize(na); - } - AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT); + CNetAddr na; + DeserializeFromFuzzingInput(buffer, na); + if (na.IsAddrV1Compatible()) { + AssertEqualAfterSerializeDeserialize(na); + } + AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT); }) FUZZ_TARGET_DESERIALIZE(service_deserialize, { - CService s; - DeserializeFromFuzzingInput(buffer, s); - if (s.IsAddrV1Compatible()) { - AssertEqualAfterSerializeDeserialize(s); - } - AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT); - CService s1; - DeserializeFromFuzzingInput(buffer, s1, INIT_PROTO_VERSION); - AssertEqualAfterSerializeDeserialize(s1, INIT_PROTO_VERSION); - assert(s1.IsAddrV1Compatible()); - CService s2; - DeserializeFromFuzzingInput(buffer, s2, INIT_PROTO_VERSION | ADDRV2_FORMAT); - AssertEqualAfterSerializeDeserialize(s2, INIT_PROTO_VERSION | ADDRV2_FORMAT); + CService s; + DeserializeFromFuzzingInput(buffer, s); + if (s.IsAddrV1Compatible()) { + AssertEqualAfterSerializeDeserialize(s); + } + AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT); + CService s1; + DeserializeFromFuzzingInput(buffer, s1, INIT_PROTO_VERSION); + AssertEqualAfterSerializeDeserialize(s1, INIT_PROTO_VERSION); + assert(s1.IsAddrV1Compatible()); + CService s2; + DeserializeFromFuzzingInput(buffer, s2, INIT_PROTO_VERSION | ADDRV2_FORMAT); + AssertEqualAfterSerializeDeserialize(s2, INIT_PROTO_VERSION | ADDRV2_FORMAT); }) FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, { - CMessageHeader mh; - DeserializeFromFuzzingInput(buffer, mh); - (void)mh.IsCommandValid(); + CMessageHeader mh; + DeserializeFromFuzzingInput(buffer, mh); + (void)mh.IsCommandValid(); }) FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_notime, { - CAddress a; - DeserializeFromFuzzingInput(buffer, a, INIT_PROTO_VERSION); - // A CAddress without nTime (as is expected under INIT_PROTO_VERSION) will roundtrip - // in all 5 formats (with/without nTime, v1/v2, network/disk) - AssertEqualAfterSerializeDeserialize(a, INIT_PROTO_VERSION); - AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); - AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); - AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); - AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); + CAddress a; + DeserializeFromFuzzingInput(buffer, a, INIT_PROTO_VERSION); + // A CAddress without nTime (as is expected under INIT_PROTO_VERSION) will roundtrip + // in all 5 formats (with/without nTime, v1/v2, network/disk) + AssertEqualAfterSerializeDeserialize(a, INIT_PROTO_VERSION); + AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); + AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); + AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); + AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); }) FUZZ_TARGET_DESERIALIZE(address_deserialize_v1_withtime, { - CAddress a; - DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION); - // A CAddress in V1 mode will roundtrip in all 4 formats that have nTime. - AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); - AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); - AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); - AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); + CAddress a; + DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION); + // A CAddress in V1 mode will roundtrip in all 4 formats that have nTime. + AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); + AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); + AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); + AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); }) FUZZ_TARGET_DESERIALIZE(address_deserialize_v2, { - CAddress a; - DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION | ADDRV2_FORMAT); - // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats - // with time if it's V1 compatible. - if (a.IsAddrV1Compatible()) { - AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); - AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); - } - AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); - AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); + CAddress a; + DeserializeFromFuzzingInput(buffer, a, PROTOCOL_VERSION | ADDRV2_FORMAT); + // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats + // with time if it's V1 compatible. + if (a.IsAddrV1Compatible()) { + AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION); + AssertEqualAfterSerializeDeserialize(a, 0, SER_DISK); + } + AssertEqualAfterSerializeDeserialize(a, PROTOCOL_VERSION | ADDRV2_FORMAT); + AssertEqualAfterSerializeDeserialize(a, ADDRV2_FORMAT, SER_DISK); }) FUZZ_TARGET_DESERIALIZE(inv_deserialize, { - CInv i; - DeserializeFromFuzzingInput(buffer, i); + CInv i; + DeserializeFromFuzzingInput(buffer, i); }) FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, { - CBloomFilter bf; - DeserializeFromFuzzingInput(buffer, bf); + CBloomFilter bf; + DeserializeFromFuzzingInput(buffer, bf); }) FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, { - CDiskBlockIndex dbi; - DeserializeFromFuzzingInput(buffer, dbi); + CDiskBlockIndex dbi; + DeserializeFromFuzzingInput(buffer, dbi); }) FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, { - CTxOut to; - auto toc = Using<TxOutCompression>(to); - DeserializeFromFuzzingInput(buffer, toc); + CTxOut to; + auto toc = Using<TxOutCompression>(to); + DeserializeFromFuzzingInput(buffer, toc); }) FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, { - BlockTransactions bt; - DeserializeFromFuzzingInput(buffer, bt); + BlockTransactions bt; + DeserializeFromFuzzingInput(buffer, bt); }) FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, { - BlockTransactionsRequest btr; - DeserializeFromFuzzingInput(buffer, btr); + BlockTransactionsRequest btr; + DeserializeFromFuzzingInput(buffer, btr); }) FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, { - SnapshotMetadata snapshot_metadata; - DeserializeFromFuzzingInput(buffer, snapshot_metadata); + SnapshotMetadata snapshot_metadata; + DeserializeFromFuzzingInput(buffer, snapshot_metadata); }) FUZZ_TARGET_DESERIALIZE(uint160_deserialize, { - uint160 u160; - DeserializeFromFuzzingInput(buffer, u160); - AssertEqualAfterSerializeDeserialize(u160); + uint160 u160; + DeserializeFromFuzzingInput(buffer, u160); + AssertEqualAfterSerializeDeserialize(u160); }) FUZZ_TARGET_DESERIALIZE(uint256_deserialize, { - uint256 u256; - DeserializeFromFuzzingInput(buffer, u256); - AssertEqualAfterSerializeDeserialize(u256); -}) - // Classes intentionally not covered in this file since their deserialization code is - // fuzzed elsewhere: - // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp - // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp + uint256 u256; + DeserializeFromFuzzingInput(buffer, u256); + AssertEqualAfterSerializeDeserialize(u256); +}) +// Classes intentionally not covered in this file since their deserialization code is +// fuzzed elsewhere: +// * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp +// * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index e9fa343896..e28e2feb0a 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -16,8 +16,6 @@ #include <pow.h> #include <protocol.h> #include <pubkey.h> -#include <rpc/util.h> -#include <script/signingprovider.h> #include <script/standard.h> #include <serialize.h> #include <streams.h> @@ -158,20 +156,6 @@ FUZZ_TARGET_INIT(integer, initialize_integer) const CKeyID key_id{u160}; const CScriptID script_id{u160}; - // CTxDestination = CNoDestination ∪ PKHash ∪ ScriptHash ∪ WitnessV0ScriptHash ∪ WitnessV0KeyHash ∪ WitnessUnknown - const PKHash pk_hash{u160}; - const ScriptHash script_hash{u160}; - const WitnessV0KeyHash witness_v0_key_hash{u160}; - const WitnessV0ScriptHash witness_v0_script_hash{u256}; - const std::vector<CTxDestination> destinations{pk_hash, script_hash, witness_v0_key_hash, witness_v0_script_hash}; - const SigningProvider store; - for (const CTxDestination& destination : destinations) { - (void)DescribeAddress(destination); - (void)EncodeDestination(destination); - (void)GetKeyForDestination(store, destination); - (void)GetScriptForDestination(destination); - (void)IsValidDestination(destination); - } { CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp index 665ca01fa1..f58bf8b316 100644 --- a/src/test/fuzz/key_io.cpp +++ b/src/test/fuzz/key_io.cpp @@ -4,9 +4,6 @@ #include <chainparams.h> #include <key_io.h> -#include <rpc/util.h> -#include <script/signingprovider.h> -#include <script/standard.h> #include <test/fuzz/fuzz.h> #include <cassert> @@ -39,12 +36,4 @@ FUZZ_TARGET_INIT(key_io, initialize_key_io) if (ext_pub_key.pubkey.size() == CPubKey::COMPRESSED_SIZE) { assert(ext_pub_key == DecodeExtPubKey(EncodeExtPubKey(ext_pub_key))); } - - const CTxDestination tx_destination = DecodeDestination(random_string); - (void)DescribeAddress(tx_destination); - (void)GetKeyForDestination(/* store */ {}, tx_destination); - (void)GetScriptForDestination(tx_destination); - (void)IsValidDestination(tx_destination); - - (void)IsValidDestinationString(random_string); } diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp index 908e9a1c83..82f3a306c5 100644 --- a/src/test/fuzz/kitchen_sink.cpp +++ b/src/test/fuzz/kitchen_sink.cpp @@ -13,6 +13,7 @@ #include <array> #include <cstdint> +#include <optional> #include <vector> namespace { @@ -46,11 +47,10 @@ FUZZ_TARGET(kitchen_sink) const OutputType output_type = fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES); const std::string& output_type_string = FormatOutputType(output_type); - OutputType output_type_parsed; - const bool parsed = ParseOutputType(output_type_string, output_type_parsed); + const std::optional<OutputType> parsed = ParseOutputType(output_type_string); assert(parsed); - assert(output_type == output_type_parsed); - (void)ParseOutputType(fuzzed_data_provider.ConsumeRandomLengthString(64), output_type_parsed); + assert(output_type == parsed.value()); + (void)ParseOutputType(fuzzed_data_provider.ConsumeRandomLengthString(64)); const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); const std::vector<bool> bits = BytesToBits(bytes); diff --git a/src/test/fuzz/multiplication_overflow.cpp b/src/test/fuzz/multiplication_overflow.cpp index 0f054529a6..c7251650c2 100644 --- a/src/test/fuzz/multiplication_overflow.cpp +++ b/src/test/fuzz/multiplication_overflow.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> @@ -10,14 +14,6 @@ #include <string> #include <vector> -#if defined(__has_builtin) -#if __has_builtin(__builtin_mul_overflow) -#define HAVE_BUILTIN_MUL_OVERFLOW -#endif -#elif defined(__GNUC__) -#define HAVE_BUILTIN_MUL_OVERFLOW -#endif - namespace { template <typename T> void TestMultiplicationOverflow(FuzzedDataProvider& fuzzed_data_provider) diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp index f9d8129ca9..6cb81901cb 100644 --- a/src/test/fuzz/netaddress.cpp +++ b/src/test/fuzz/netaddress.cpp @@ -54,7 +54,7 @@ FUZZ_TARGET(netaddress) (void)net_addr.IsRFC3927(); (void)net_addr.IsRFC3964(); if (net_addr.IsRFC4193()) { - assert(net_addr.GetNetwork() == Network::NET_ONION || net_addr.GetNetwork() == Network::NET_INTERNAL || net_addr.GetNetwork() == Network::NET_UNROUTABLE); + assert(net_addr.GetNetwork() == Network::NET_INTERNAL || net_addr.GetNetwork() == Network::NET_UNROUTABLE); } (void)net_addr.IsRFC4380(); (void)net_addr.IsRFC4843(); diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp index 51956bbe9e..447f32ed16 100644 --- a/src/test/fuzz/prevector.cpp +++ b/src/test/fuzz/prevector.cpp @@ -206,10 +206,14 @@ public: FUZZ_TARGET(prevector) { + // Pick an arbitrary upper bound to limit the runtime and avoid timeouts on + // inputs. + int limit_max_ops{3000}; + FuzzedDataProvider prov(buffer.data(), buffer.size()); prevector_tester<8, int> test; - while (prov.remaining_bytes()) { + while (--limit_max_ops >= 0 && prov.remaining_bytes()) { switch (prov.ConsumeIntegralInRange<int>(0, 13 + 3 * (test.size() > 0))) { case 0: test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), prov.ConsumeIntegral<int>()); diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index c4e4d4c785..7b99193ad0 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -58,19 +58,7 @@ void initialize_process_message() static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); g_setup = testing_setup.get(); - - // Temporary debug for https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=35027 - { - LOCK(::cs_main); - assert(CheckDiskSpace(gArgs.GetDataDirNet())); - assert(CheckDiskSpace(gArgs.GetDataDirNet(), 48 * 2 * 2 * g_setup->m_node.chainman->ActiveChainstate().CoinsTip().GetCacheSize())); - } for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { - { - LOCK(::cs_main); - assert(CheckDiskSpace(gArgs.GetDataDirNet())); - assert(CheckDiskSpace(gArgs.GetDataDirNet(), 48 * 2 * 2 * g_setup->m_node.chainman->ActiveChainstate().CoinsTip().GetCacheSize())); - } MineBlock(g_setup->m_node, CScript() << OP_TRUE); } SyncWithValidationInterfaceQueue(); diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp index 07059cce76..3b33115e72 100644 --- a/src/test/fuzz/rolling_bloom_filter.cpp +++ b/src/test/fuzz/rolling_bloom_filter.cpp @@ -16,12 +16,16 @@ FUZZ_TARGET(rolling_bloom_filter) { + // Pick an arbitrary upper bound to limit the runtime and avoid timeouts on + // inputs. + int limit_max_ops{3000}; + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CRollingBloomFilter rolling_bloom_filter{ fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 1000), 0.999 / fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, std::numeric_limits<unsigned int>::max())}; - while (fuzzed_data_provider.remaining_bytes() > 0) { + while (--limit_max_ops >= 0 && fuzzed_data_provider.remaining_bytes() > 0) { CallOneOf( fuzzed_data_provider, [&] { @@ -32,13 +36,10 @@ FUZZ_TARGET(rolling_bloom_filter) assert(present); }, [&] { - const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider); - if (!u256) { - return; - } - (void)rolling_bloom_filter.contains(*u256); - rolling_bloom_filter.insert(*u256); - const bool present = rolling_bloom_filter.contains(*u256); + const uint256 u256{ConsumeUInt256(fuzzed_data_provider)}; + (void)rolling_bloom_filter.contains(u256); + rolling_bloom_filter.insert(u256); + const bool present = rolling_bloom_filter.contains(u256); assert(present); }, [&] { diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index b87bcf2ef5..950ee45d1d 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -6,8 +6,10 @@ #include <compressor.h> #include <core_io.h> #include <core_memusage.h> +#include <key_io.h> #include <policy/policy.h> #include <pubkey.h> +#include <rpc/util.h> #include <script/descriptor.h> #include <script/interpreter.h> #include <script/script.h> @@ -184,26 +186,26 @@ FUZZ_TARGET_INIT(script, initialize_script) } { - WitnessUnknown witness_unknown_1{}; - witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); - const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40); - witness_unknown_1.length = witness_unknown_program_1.size(); - std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown_1.program); - - WitnessUnknown witness_unknown_2{}; - witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); - const std::vector<uint8_t> witness_unknown_program_2 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40); - witness_unknown_2.length = witness_unknown_program_2.size(); - std::copy(witness_unknown_program_2.begin(), witness_unknown_program_2.end(), witness_unknown_2.program); - - (void)(witness_unknown_1 == witness_unknown_2); - (void)(witness_unknown_1 < witness_unknown_2); - } + const CTxDestination tx_destination_1{ + fuzzed_data_provider.ConsumeBool() ? + DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) : + ConsumeTxDestination(fuzzed_data_provider)}; + const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)}; + const std::string encoded_dest{EncodeDestination(tx_destination_1)}; + const UniValue json_dest{DescribeAddress(tx_destination_1)}; + Assert(tx_destination_1 == DecodeDestination(encoded_dest)); + (void)GetKeyForDestination(/* store */ {}, tx_destination_1); + const CScript dest{GetScriptForDestination(tx_destination_1)}; + const bool valid{IsValidDestination(tx_destination_1)}; + Assert(dest.empty() != valid); + + Assert(valid == IsValidDestinationString(encoded_dest)); - { - const CTxDestination tx_destination_1 = ConsumeTxDestination(fuzzed_data_provider); - const CTxDestination tx_destination_2 = ConsumeTxDestination(fuzzed_data_provider); - (void)(tx_destination_1 == tx_destination_2); (void)(tx_destination_1 < tx_destination_2); + if (tx_destination_1 == tx_destination_2) { + Assert(encoded_dest == EncodeDestination(tx_destination_2)); + Assert(json_dest.write() == DescribeAddress(tx_destination_2).write()); + Assert(dest == GetScriptForDestination(tx_destination_2)); + } } } diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 286375f7ae..0c1b45b86c 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -66,8 +66,7 @@ FUZZ_TARGET(string) (void)ParseNonRFCJSONValue(random_string_1); } catch (const std::runtime_error&) { } - OutputType output_type; - (void)ParseOutputType(random_string_1, output_type); + (void)ParseOutputType(random_string_1); (void)RemovePrefix(random_string_1, random_string_2); (void)ResolveErrMsg(random_string_1, random_string_2); try { diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index bab34ea340..dadf772bc1 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -112,6 +112,10 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chain FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) { + // Pick an arbitrary upper bound to limit the runtime and avoid timeouts on + // inputs. + int limit_max_ops{300}; + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const auto& node = g_setup->m_node; auto& chainstate = node.chainman->ActiveChainstate(); @@ -142,7 +146,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) return c.out.nValue; }; - while (fuzzed_data_provider.ConsumeBool()) { + while (--limit_max_ops >= 0 && fuzzed_data_provider.ConsumeBool()) { { // Total supply is the mempool fee + all outpoints CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())}; @@ -285,6 +289,10 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool) FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) { + // Pick an arbitrary upper bound to limit the runtime and avoid timeouts on + // inputs. + int limit_max_ops{300}; + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const auto& node = g_setup->m_node; auto& chainstate = node.chainman->ActiveChainstate(); @@ -305,7 +313,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool) CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1}; MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_); - while (fuzzed_data_provider.ConsumeBool()) { + while (--limit_max_ops >= 0 && fuzzed_data_provider.ConsumeBool()) { const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids); if (fuzzed_data_provider.ConsumeBool()) { diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index bcf0b0ce72..0d87f687d3 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <pubkey.h> #include <test/fuzz/util.h> #include <test/util/script.h> #include <util/rbf.h> @@ -304,3 +305,196 @@ uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept }) : fuzzed_data_provider.ConsumeIntegral<uint32_t>(); } + +CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + CTxDestination tx_destination; + const size_t call_size{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)}; + }, + [&] { + tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}}; + }, + [&] { + WitnessUnknown witness_unknown{}; + witness_unknown.version = fuzzed_data_provider.ConsumeIntegralInRange(2, 16); + std::vector<uint8_t> witness_unknown_program_1{fuzzed_data_provider.ConsumeBytes<uint8_t>(40)}; + if (witness_unknown_program_1.size() < 2) { + witness_unknown_program_1 = {0, 0}; + } + 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; + })}; + Assert(call_size == std::variant_size_v<CTxDestination>); + return tx_destination; +} + +CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept +{ + // Avoid: + // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long' + // + // 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)); + 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, {}}; +} + +bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept +{ + for (const CTxIn& tx_in : tx.vin) { + const Coin& coin = inputs.AccessCoin(tx_in.prevout); + if (coin.IsSpent()) { + return true; + } + } + return false; +} + +CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + 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) { + in_addr v4_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; +} + +FILE* FuzzedFileProvider::open() +{ + SetFuzzedErrNo(m_fuzzed_data_provider); + if (m_fuzzed_data_provider.ConsumeBool()) { + return nullptr; + } + std::string mode; + CallOneOf( + m_fuzzed_data_provider, + [&] { + mode = "r"; + }, + [&] { + mode = "r+"; + }, + [&] { + mode = "w"; + }, + [&] { + mode = "w+"; + }, + [&] { + mode = "a"; + }, + [&] { + mode = "a+"; + }); +#if defined _GNU_SOURCE && !defined __ANDROID__ + 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 +} + +ssize_t FuzzedFileProvider::read(void* cookie, char* buf, size_t size) +{ + FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; + SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); + 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(fuzzed_file->m_offset, (int64_t)random_bytes.size())) { + return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; + } + fuzzed_file->m_offset += random_bytes.size(); + return random_bytes.size(); +} + +ssize_t FuzzedFileProvider::write(void* cookie, const char* buf, size_t size) +{ + FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; + SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); + const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size); + if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) { + return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; + } + fuzzed_file->m_offset += n; + return n; +} + +int FuzzedFileProvider::seek(void* cookie, int64_t* offset, int whence) +{ + assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END); + FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; + SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); + 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; + } else if (whence == SEEK_END) { + const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096); + if (AdditionOverflow(n, *offset)) { + return -1; + } + new_offset = n + *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); +} + +int FuzzedFileProvider::close(void* cookie) +{ + FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; + SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); + return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0); +} diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 023dcdb3e5..bb017b3497 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -37,7 +37,7 @@ #include <vector> template <typename... Callables> -void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) +size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) { constexpr size_t call_size{sizeof...(callables)}; static_assert(call_size >= 1); @@ -45,6 +45,7 @@ void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) size_t i{0}; ((i++ == call_index ? callables() : void()), ...); + return call_size; } template <typename Collection> @@ -163,51 +164,9 @@ template <typename WeakEnumType, size_t size> return UintToArith256(ConsumeUInt256(fuzzed_data_provider)); } -[[nodiscard]] inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept -{ - // Avoid: - // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long' - // - // 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)); - 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, {}}; -} +[[nodiscard]] CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept; -[[nodiscard]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - CTxDestination tx_destination; - 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<uint32_t>(); - 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; - }); - return tx_destination; -} +[[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept; template <typename T> [[nodiscard]] bool MultiplicationOverflow(const T i, const T j) noexcept @@ -243,16 +202,7 @@ template <class T> return std::numeric_limits<T>::max() - i < j; } -[[nodiscard]] inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept -{ - for (const CTxIn& tx_in : tx.vin) { - const Coin& coin = inputs.AccessCoin(tx_in.prevout); - if (coin.IsSpent()) { - return true; - } - } - return false; -} +[[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept; /** * Sets errno to a value selected from the given std::array `errnos`. @@ -287,27 +237,7 @@ inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept return result; } -inline CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept -{ - 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) { - in_addr v4_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; -} +CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept; inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept { @@ -357,112 +287,15 @@ public: { } - FILE* open() - { - SetFuzzedErrNo(m_fuzzed_data_provider); - if (m_fuzzed_data_provider.ConsumeBool()) { - return nullptr; - } - std::string mode; - CallOneOf( - m_fuzzed_data_provider, - [&] { - mode = "r"; - }, - [&] { - mode = "r+"; - }, - [&] { - mode = "w"; - }, - [&] { - mode = "w+"; - }, - [&] { - mode = "a"; - }, - [&] { - mode = "a+"; - }); -#if defined _GNU_SOURCE && !defined __ANDROID__ - 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 - } + FILE* open(); - static ssize_t read(void* cookie, char* buf, size_t size) - { - FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; - SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); - 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(fuzzed_file->m_offset, (int64_t)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 read(void* cookie, char* buf, size_t size); - static ssize_t write(void* cookie, const char* buf, size_t size) - { - FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; - SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); - const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size); - if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) { - return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; - } - fuzzed_file->m_offset += n; - return n; - } + static ssize_t write(void* cookie, const char* buf, size_t size); - static int seek(void* cookie, int64_t* offset, int whence) - { - assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END); - FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; - SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); - 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; - } else if (whence == SEEK_END) { - const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096); - if (AdditionOverflow(n, *offset)) { - return -1; - } - new_offset = n + *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 seek(void* cookie, int64_t* offset, int whence); - static int close(void* cookie) - { - FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie; - SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider); - return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0); - } + static int close(void* cookie); }; [[nodiscard]] inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept |