diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -35,244 +36,178 @@ static const auto verify_handle = std::make_unique(); } -void test_one_input(const std::vector &buffer) { +namespace { + +struct invalid_fuzzing_input_exception : public std::exception {}; + +template CDataStream Serialize(const T &obj) { + CDataStream ds(SER_NETWORK, INIT_PROTO_VERSION); + ds << obj; + return ds; +} + +template T Deserialize(CDataStream ds) { + T obj; + ds >> obj; + return obj; +} + +template +void DeserializeFromFuzzingInput(const std::vector &buffer, T &obj) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); try { - int nVersion; - ds >> nVersion; - ds.SetVersion(nVersion); + int version; + ds >> version; + ds.SetVersion(version); } catch (const std::ios_base::failure &) { - return; + throw invalid_fuzzing_input_exception(); } - -#if BLOCK_FILTER_DESERIALIZE try { - BlockFilter block_filter; - ds >> block_filter; + ds >> obj; } catch (const std::ios_base::failure &) { + throw invalid_fuzzing_input_exception(); } -#elif ADDR_INFO_DESERIALIZE + assert(buffer.empty() || !Serialize(obj).empty()); +} + +template void AssertEqualAfterSerializeDeserialize(const T &obj) { + assert(Deserialize(Serialize(obj)) == obj); +} + +} // namespace + +void test_one_input(const std::vector &buffer) { try { +#if BLOCK_FILTER_DESERIALIZE + BlockFilter block_filter; + DeserializeFromFuzzingInput(buffer, block_filter); +#elif ADDR_INFO_DESERIALIZE CAddrInfo addr_info; - ds >> addr_info; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, addr_info); #elif BLOCK_FILE_INFO_DESERIALIZE - try { CBlockFileInfo block_file_info; - ds >> block_file_info; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, block_file_info); #elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE - try { CBlockHeaderAndShortTxIDs block_header_and_short_txids; - ds >> block_header_and_short_txids; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, block_header_and_short_txids); #elif FEE_RATE_DESERIALIZE - try { CFeeRate fee_rate; - ds >> fee_rate; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, fee_rate); + AssertEqualAfterSerializeDeserialize(fee_rate); #elif MERKLE_BLOCK_DESERIALIZE - try { CMerkleBlock merkle_block; - ds >> merkle_block; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, merkle_block); #elif OUT_POINT_DESERIALIZE - try { COutPoint out_point; - ds >> out_point; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, out_point); + AssertEqualAfterSerializeDeserialize(out_point); #elif PARTIAL_MERKLE_TREE_DESERIALIZE - try { CPartialMerkleTree partial_merkle_tree; - ds >> partial_merkle_tree; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, partial_merkle_tree); #elif PUB_KEY_DESERIALIZE - try { CPubKey pub_key; - ds >> pub_key; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, pub_key); + // TODO: The following equivalence should hold for CPubKey? Fix. + // AssertEqualAfterSerializeDeserialize(pub_key); #elif SCRIPT_DESERIALIZE - try { CScript script; - ds >> script; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, script); #elif SUB_NET_DESERIALIZE - try { CSubNet sub_net; - ds >> sub_net; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, sub_net); + AssertEqualAfterSerializeDeserialize(sub_net); #elif TX_IN_DESERIALIZE - try { CTxIn tx_in; - ds >> tx_in; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, tx_in); + AssertEqualAfterSerializeDeserialize(tx_in); #elif FLAT_FILE_POS_DESERIALIZE - try { FlatFilePos flat_file_pos; - ds >> flat_file_pos; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, flat_file_pos); + AssertEqualAfterSerializeDeserialize(flat_file_pos); #elif KEY_ORIGIN_INFO_DESERIALIZE - try { KeyOriginInfo key_origin_info; - ds >> key_origin_info; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, key_origin_info); + AssertEqualAfterSerializeDeserialize(key_origin_info); #elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE - try { PartiallySignedTransaction partially_signed_transaction; - ds >> partially_signed_transaction; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, partially_signed_transaction); #elif PREFILLED_TRANSACTION_DESERIALIZE - try { PrefilledTransaction prefilled_transaction; - ds >> prefilled_transaction; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, prefilled_transaction); #elif PSBT_INPUT_DESERIALIZE - try { PSBTInput psbt_input; - ds >> psbt_input; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, psbt_input); #elif PSBT_OUTPUT_DESERIALIZE - try { PSBTOutput psbt_output; - ds >> psbt_output; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, psbt_output); #elif BLOCK_DESERIALIZE - try { CBlock block; - ds >> block; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, block); #elif BLOCKLOCATOR_DESERIALIZE - try { CBlockLocator bl; - ds >> bl; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, bl); #elif BLOCKMERKLEROOT - try { CBlock block; - ds >> block; + DeserializeFromFuzzingInput(buffer, block); bool mutated; BlockMerkleRoot(block, &mutated); - } catch (const std::ios_base::failure &) { - } #elif ADDRMAN_DESERIALIZE - try { CAddrMan am; - ds >> am; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, am); #elif BLOCKHEADER_DESERIALIZE - try { CBlockHeader bh; - ds >> bh; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, bh); #elif BANENTRY_DESERIALIZE - try { CBanEntry be; - ds >> be; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, be); #elif TXUNDO_DESERIALIZE - try { CTxUndo tu; - ds >> tu; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, tu); #elif BLOCKUNDO_DESERIALIZE - try { CBlockUndo bu; - ds >> bu; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, bu); #elif COINS_DESERIALIZE - try { Coin coin; - ds >> coin; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, coin); #elif NETADDR_DESERIALIZE - try { CNetAddr na; - ds >> na; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, na); + AssertEqualAfterSerializeDeserialize(na); #elif SERVICE_DESERIALIZE - try { CService s; - ds >> s; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, s); + AssertEqualAfterSerializeDeserialize(s); #elif MESSAGEHEADER_DESERIALIZE - CMessageHeader::MessageMagic pchMessageStart = {0x00, 0x00, 0x00, 0x00}; - try { + const CMessageHeader::MessageMagic pchMessageStart = {0x00, 0x00, 0x00, + 0x00}; CMessageHeader mh(pchMessageStart); - ds >> mh; + DeserializeFromFuzzingInput(buffer, mh); (void)mh.IsValidWithoutConfig(pchMessageStart); - } catch (const std::ios_base::failure &) { - } #elif ADDRESS_DESERIALIZE - try { CAddress a; - ds >> a; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, a); #elif INV_DESERIALIZE - try { CInv i; - ds >> i; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, i); #elif BLOOMFILTER_DESERIALIZE - try { CBloomFilter bf; - ds >> bf; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, bf); #elif DISKBLOCKINDEX_DESERIALIZE - try { CDiskBlockIndex dbi; - ds >> dbi; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, dbi); #elif TXOUTCOMPRESSOR_DESERIALIZE - CTxOut to; - CTxOutCompressor toc(to); - try { - ds >> toc; - } catch (const std::ios_base::failure &) { - } + CTxOut to; + CTxOutCompressor toc(to); + DeserializeFromFuzzingInput(buffer, toc); #elif BLOCKTRANSACTIONS_DESERIALIZE - try { BlockTransactions bt; - ds >> bt; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, bt); #elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE - try { BlockTransactionsRequest btr; - ds >> btr; - } catch (const std::ios_base::failure &) { - } + DeserializeFromFuzzingInput(buffer, btr); #else #error Need at least one fuzz target to compile #endif + } catch (const invalid_fuzzing_input_exception &) { + } }