aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz')
-rw-r--r--src/test/fuzz/fuzz.cpp72
-rw-r--r--src/test/fuzz/http_request.cpp15
-rw-r--r--src/test/fuzz/miniscript_decode.cpp72
-rw-r--r--src/test/fuzz/net.cpp10
-rw-r--r--src/test/fuzz/node_eviction.cpp2
-rw-r--r--src/test/fuzz/script_format.cpp4
-rw-r--r--src/test/fuzz/transaction.cpp4
-rw-r--r--src/test/fuzz/tx_pool.cpp14
-rw-r--r--src/test/fuzz/util.cpp11
9 files changed, 157 insertions, 47 deletions
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index a490bbfa1d..59adec075e 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -10,7 +10,9 @@
#include <test/util/setup_common.h>
#include <util/check.h>
#include <util/sock.h>
+#include <util/time.h>
+#include <csignal>
#include <cstdint>
#include <exception>
#include <fstream>
@@ -59,6 +61,7 @@ void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target,
Assert(it_ins.second);
}
+static std::string_view g_fuzz_target;
static TypeTestOneInput* g_test_one_input{nullptr};
void initialize()
@@ -92,9 +95,12 @@ void initialize()
should_abort = true;
}
Assert(!should_abort);
- std::string_view fuzz_target{Assert(std::getenv("FUZZ"))};
- const auto it = FuzzTargets().find(fuzz_target);
- Assert(it != FuzzTargets().end());
+ g_fuzz_target = Assert(std::getenv("FUZZ"));
+ const auto it = FuzzTargets().find(g_fuzz_target);
+ if (it == FuzzTargets().end()) {
+ std::cerr << "No fuzzer for " << g_fuzz_target << "." << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
Assert(!g_test_one_input);
g_test_one_input = &std::get<0>(it->second);
std::get<1>(it->second)();
@@ -112,6 +118,35 @@ static bool read_stdin(std::vector<uint8_t>& data)
}
#endif
+#if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && !defined(__AFL_LOOP)
+static bool read_file(fs::path p, std::vector<uint8_t>& data)
+{
+ uint8_t buffer[1024];
+ FILE* f = fsbridge::fopen(p, "rb");
+ if (f == nullptr) return false;
+ do {
+ const size_t length = fread(buffer, sizeof(uint8_t), sizeof(buffer), f);
+ if (ferror(f)) return false;
+ data.insert(data.end(), buffer, buffer + length);
+ } while (!feof(f));
+ fclose(f);
+ return true;
+}
+#endif
+
+#if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && !defined(__AFL_LOOP)
+static fs::path g_input_path;
+void signal_handler(int signal)
+{
+ if (signal == SIGABRT) {
+ std::cerr << "Error processing input " << g_input_path << std::endl;
+ } else {
+ std::cerr << "Unexpected signal " << signal << " received\n";
+ }
+ std::_Exit(EXIT_FAILURE);
+}
+#endif
+
// This function is used by libFuzzer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
@@ -151,10 +186,37 @@ int main(int argc, char** argv)
}
#else
std::vector<uint8_t> buffer;
- if (!read_stdin(buffer)) {
+ if (argc <= 1) {
+ if (!read_stdin(buffer)) {
+ return 0;
+ }
+ test_one_input(buffer);
return 0;
}
- test_one_input(buffer);
+ std::signal(SIGABRT, signal_handler);
+ int64_t start_time = GetTimeSeconds();
+ int tested = 0;
+ for (int i = 1; i < argc; ++i) {
+ fs::path input_path(*(argv + i));
+ if (fs::is_directory(input_path)) {
+ for (fs::directory_iterator it(input_path); it != fs::directory_iterator(); ++it) {
+ if (!fs::is_regular_file(it->path())) continue;
+ g_input_path = it->path();
+ Assert(read_file(it->path(), buffer));
+ test_one_input(buffer);
+ ++tested;
+ buffer.clear();
+ }
+ } else {
+ g_input_path = input_path;
+ Assert(read_file(input_path, buffer));
+ test_one_input(buffer);
+ ++tested;
+ buffer.clear();
+ }
+ }
+ int64_t end_time = GetTimeSeconds();
+ std::cout << g_fuzz_target << ": succeeded against " << tested << " files in " << (end_time - start_time) << "s." << std::endl;
#endif
return 0;
}
diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp
index e3b62032bc..916e90e986 100644
--- a/src/test/fuzz/http_request.cpp
+++ b/src/test/fuzz/http_request.cpp
@@ -19,23 +19,8 @@
#include <string>
#include <vector>
-// workaround for libevent versions before 2.1.1,
-// when internal functions didn't have underscores at the end
-#if LIBEVENT_VERSION_NUMBER < 0x02010100
-extern "C" int evhttp_parse_firstline(struct evhttp_request*, struct evbuffer*);
-extern "C" int evhttp_parse_headers(struct evhttp_request*, struct evbuffer*);
-inline int evhttp_parse_firstline_(struct evhttp_request* r, struct evbuffer* b)
-{
- return evhttp_parse_firstline(r, b);
-}
-inline int evhttp_parse_headers_(struct evhttp_request* r, struct evbuffer* b)
-{
- return evhttp_parse_headers(r, b);
-}
-#else
extern "C" int evhttp_parse_firstline_(struct evhttp_request*, struct evbuffer*);
extern "C" int evhttp_parse_headers_(struct evhttp_request*, struct evbuffer*);
-#endif
std::string RequestMethodString(HTTPRequest::RequestMethod m);
diff --git a/src/test/fuzz/miniscript_decode.cpp b/src/test/fuzz/miniscript_decode.cpp
new file mode 100644
index 0000000000..4cc0a1be8f
--- /dev/null
+++ b/src/test/fuzz/miniscript_decode.cpp
@@ -0,0 +1,72 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <core_io.h>
+#include <hash.h>
+#include <key.h>
+#include <script/miniscript.h>
+#include <script/script.h>
+#include <span.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <util/strencodings.h>
+
+#include <optional>
+
+using miniscript::operator""_mst;
+
+
+struct Converter {
+ typedef CPubKey Key;
+
+ bool ToString(const Key& key, std::string& ret) const {
+ ret = HexStr(key);
+ return true;
+ }
+ const std::vector<unsigned char> ToPKBytes(const Key& key) const {
+ return {key.begin(), key.end()};
+ }
+ const std::vector<unsigned char> ToPKHBytes(const Key& key) const {
+ const auto h = Hash160(key);
+ return {h.begin(), h.end()};
+ }
+
+ template<typename I>
+ bool FromString(I first, I last, Key& key) const {
+ const auto bytes = ParseHex(std::string(first, last));
+ key.Set(bytes.begin(), bytes.end());
+ return key.IsValid();
+ }
+ template<typename I>
+ bool FromPKBytes(I first, I last, CPubKey& key) const {
+ key.Set(first, last);
+ return key.IsValid();
+ }
+ template<typename I>
+ bool FromPKHBytes(I first, I last, CPubKey& key) const {
+ assert(last - first == 20);
+ return false;
+ }
+};
+
+const Converter CONVERTER;
+
+FUZZ_TARGET(miniscript_decode)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const std::optional<CScript> script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
+ if (!script) return;
+
+ const auto ms = miniscript::FromScript(*script, CONVERTER);
+ if (!ms) return;
+
+ // We can roundtrip it to its string representation.
+ std::string ms_str;
+ assert(ms->ToString(CONVERTER, ms_str));
+ assert(*miniscript::FromString(ms_str, CONVERTER) == *ms);
+ // The Script representation must roundtrip since we parsed it this way the first time.
+ const CScript ms_script = ms->ToScript(CONVERTER);
+ assert(ms_script == *script);
+}
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index fb11ea36ce..4981287152 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -52,16 +52,6 @@ FUZZ_TARGET_INIT(net, initialize_net)
}
},
[&] {
- const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
- if (!inv_opt) {
- return;
- }
- node.AddKnownTx(inv_opt->hash);
- },
- [&] {
- node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
- },
- [&] {
const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (!service_opt) {
return;
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
index 2e90085744..6a363f00f7 100644
--- a/src/test/fuzz/node_eviction.cpp
+++ b/src/test/fuzz/node_eviction.cpp
@@ -26,7 +26,7 @@ FUZZ_TARGET(node_eviction)
/*m_last_block_time=*/std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<int64_t>()},
/*m_last_tx_time=*/std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<int64_t>()},
/*fRelevantServices=*/fuzzed_data_provider.ConsumeBool(),
- /*fRelayTxes=*/fuzzed_data_provider.ConsumeBool(),
+ /*m_relay_txs=*/fuzzed_data_provider.ConsumeBool(),
/*fBloomFilter=*/fuzzed_data_provider.ConsumeBool(),
/*nKeyedNetGroup=*/fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
/*prefer_evict=*/fuzzed_data_provider.ConsumeBool(),
diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp
index 241bdfe666..9186746bcf 100644
--- a/src/test/fuzz/script_format.cpp
+++ b/src/test/fuzz/script_format.cpp
@@ -29,7 +29,5 @@ FUZZ_TARGET_INIT(script_format, initialize_script_format)
(void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool());
UniValue o1(UniValue::VOBJ);
- ScriptPubKeyToUniv(script, o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool());
- UniValue o3(UniValue::VOBJ);
- ScriptToUniv(script, o3);
+ ScriptToUniv(script, /*out=*/o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool(), /*include_address=*/fuzzed_data_provider.ConsumeBool());
}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 6dd8a36692..273aa0dc5c 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -102,6 +102,6 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)IsWitnessStandard(tx, coins_view_cache);
UniValue u(UniValue::VOBJ);
- TxToUniv(tx, /*hashBlock=*/uint256::ZERO, u);
- TxToUniv(tx, /*hashBlock=*/uint256::ONE, u);
+ TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u);
+ TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u);
}
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index df5b271d06..f686f4fd86 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -234,14 +234,18 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
::fRequireStandard = fuzzed_data_provider.ConsumeBool();
- // Make sure ProcessNewPackage on one transaction works and always fully validates the transaction.
+ // Make sure ProcessNewPackage on one transaction works.
// The result is not guaranteed to be the same as what is returned by ATMP.
const auto result_package = WITH_LOCK(::cs_main,
return ProcessNewPackage(chainstate, tx_pool, {tx}, true));
- auto it = result_package.m_tx_results.find(tx->GetWitnessHash());
- Assert(it != result_package.m_tx_results.end());
- Assert(it->second.m_result_type == MempoolAcceptResult::ResultType::VALID ||
- it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
+ // If something went wrong due to a package-specific policy, it might not return a
+ // validation result for the transaction.
+ if (result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
+ auto it = result_package.m_tx_results.find(tx->GetWitnessHash());
+ Assert(it != result_package.m_tx_results.end());
+ Assert(it->second.m_result_type == MempoolAcceptResult::ResultType::VALID ||
+ it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
+ }
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index f0c1b0d147..6766fbf2d9 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -225,7 +225,7 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman,
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 = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
- const bool filter_txs = fuzzed_data_provider.ConsumeBool();
+ const bool relay_txs{fuzzed_data_provider.ConsumeBool()};
const CNetMsgMaker mm{0};
@@ -241,7 +241,7 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman,
uint64_t{1}, // dummy nonce
std::string{}, // dummy subver
int32_t{}, // dummy starting_height
- filter_txs),
+ relay_txs),
};
(void)connman.ReceiveMsgFrom(node, msg_version);
@@ -255,10 +255,9 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman,
assert(node.nVersion == version);
assert(node.GetCommonVersion() == std::min(version, PROTOCOL_VERSION));
assert(node.nServices == remote_services);
- if (node.m_tx_relay != nullptr) {
- LOCK(node.m_tx_relay->cs_filter);
- assert(node.m_tx_relay->fRelayTxes == filter_txs);
- }
+ CNodeStateStats statestats;
+ assert(peerman.GetNodeStateStats(node.GetId(), statestats));
+ assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));
node.m_permissionFlags = permission_flags;
if (successfully_connected) {
CSerializedNetMsg msg_verack{mm.Make(NetMsgType::VERACK)};