From 6f7c7567c578b5a41f8e90ce4491e40f7faeaa56 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 26 Oct 2021 17:26:16 +0200 Subject: [PATCH] fuzz: parse the command line arguments in fuzz tests Retrieve the command line arguments from the fuzzer and save them for later retrieval by `BasicTestingSetup` so that we gain extra flexibility of passing any config options on the test command line, e.g.: ``` FUZZ=addrman ./src/test/fuzz/fuzz --checkaddrman=5 ``` A fuzz test should call `MakeNoLogFileContext<>()` in its initialize function in order to invoke the constructor of `BasicTestingSetup`, which sets `gArgs`. --- doc/fuzzing.md | 9 +++++++++ src/test/fuzz/fuzz.cpp | 24 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/fuzzing.md b/doc/fuzzing.md index 73d04837f1..9abfbc9213 100644 --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -71,6 +71,15 @@ block^@M-^?M-^?M-^?M-^?M-^?nM-^?M-^? In this case the fuzzer managed to create a `block` message which when passed to `ProcessMessage(...)` increased coverage. +It is possible to specify `bitcoind` arguments to the `fuzz` executable. +Depending on the test, they may be ignored or consumed and alter the behavior +of the test. Just make sure to use double-dash to distinguish them from the +fuzzer's own arguments: + +```sh +$ FUZZ=address_deserialize_v2 src/test/fuzz/fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5 --printtoconsole=1 +``` + ## Fuzzing corpora The project's collection of seed corpora is found in the [`bitcoin-core/qa-assets`](https://github.com/bitcoin-core/qa-assets) repo. diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 1c994a53cf..e9debd8c45 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -20,7 +20,28 @@ const std::function G_TEST_LOG_FUN{}; -const std::function()> G_TEST_COMMAND_LINE_ARGUMENTS{}; +/** + * A copy of the command line arguments that start with `--`. + * First `LLVMFuzzerInitialize()` is called, which saves the arguments to `g_args`. + * Later, depending on the fuzz test, `G_TEST_COMMAND_LINE_ARGUMENTS()` may be + * called by `BasicTestingSetup` constructor to fetch those arguments and store + * them in `BasicTestingSetup::m_node::args`. + */ +static std::vector g_args; + +static void SetArgs(int argc, char** argv) { + for (int i = 1; i < argc; ++i) { + // Only take into account arguments that start with `--`. The others are for the fuzz engine: + // `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5` + if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') { + g_args.push_back(argv[i]); + } + } +} + +const std::function()> G_TEST_COMMAND_LINE_ARGUMENTS = []() { + return g_args; +}; std::map>& FuzzTargets() { @@ -98,6 +119,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // This function is used by libFuzzer extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + SetArgs(*argc, *argv); initialize(); return 0; }