Bitcoin Core 22.99.0
P2P Digital Currency
fuzz.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2021 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <test/fuzz/fuzz.h>
6
7#include <netaddress.h>
8#include <netbase.h>
10#include <util/check.h>
11#include <util/sock.h>
12
13#include <cstdint>
14#include <exception>
15#include <memory>
16#include <string>
17#include <unistd.h>
18#include <vector>
19
20const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
21
22std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
23{
24 static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;
25 return g_fuzz_targets;
26}
27
29{
30 const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init), hidden);
31 Assert(it_ins.second);
32}
33
35
37{
38 // Terminate immediately if a fuzzing harness ever tries to create a TCP socket.
39 CreateSock = [](const CService&) -> std::unique_ptr<Sock> { std::terminate(); };
40
41 // Terminate immediately if a fuzzing harness ever tries to perform a DNS lookup.
42 g_dns_lookup = [](const std::string& name, bool allow_lookup) {
43 if (allow_lookup) {
44 std::terminate();
45 }
46 return WrappedGetAddrInfo(name, false);
47 };
48
49 bool should_abort{false};
50 if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
51 for (const auto& t : FuzzTargets()) {
52 if (std::get<2>(t.second)) continue;
53 std::cout << t.first << std::endl;
54 }
55 should_abort = true;
56 }
57 if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) {
58 std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl;
59 std::ofstream out_stream(out_path, std::ios::binary);
60 for (const auto& t : FuzzTargets()) {
61 if (std::get<2>(t.second)) continue;
62 out_stream << t.first << std::endl;
63 }
64 should_abort = true;
65 }
66 Assert(!should_abort);
67 std::string_view fuzz_target{Assert(std::getenv("FUZZ"))};
68 const auto it = FuzzTargets().find(fuzz_target);
69 Assert(it != FuzzTargets().end());
71 g_test_one_input = &std::get<0>(it->second);
72 std::get<1>(it->second)();
73}
74
75#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
76static bool read_stdin(std::vector<uint8_t>& data)
77{
78 uint8_t buffer[1024];
79 ssize_t length = 0;
80 while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
81 data.insert(data.end(), buffer, buffer + length);
82 }
83 return length == 0;
84}
85#endif
86
87// This function is used by libFuzzer
88extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
89{
90 static const auto& test_one_input = *Assert(g_test_one_input);
91 test_one_input({data, size});
92 return 0;
93}
94
95// This function is used by libFuzzer
96extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
97{
98 initialize();
99 return 0;
100}
101
102#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
103int main(int argc, char** argv)
104{
105 initialize();
106 static const auto& test_one_input = *Assert(g_test_one_input);
107#ifdef __AFL_INIT
108 // Enable AFL deferred forkserver mode. Requires compilation using
109 // afl-clang-fast++. See fuzzing.md for details.
110 __AFL_INIT();
111#endif
112
113#ifdef __AFL_LOOP
114 // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
115 // See fuzzing.md for details.
116 while (__AFL_LOOP(1000)) {
117 std::vector<uint8_t> buffer;
118 if (!read_stdin(buffer)) {
119 continue;
120 }
121 test_one_input(buffer);
122 }
123#else
124 std::vector<uint8_t> buffer;
125 if (!read_stdin(buffer)) {
126 return 0;
127 }
128 test_one_input(buffer);
129#endif
130 return 0;
131}
132#endif
int main(int argc, char **argv)
#define Assert(val)
Identity function.
Definition: check.h:57
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:523
void initialize()
Definition: fuzz.cpp:36
const std::function< void(const std::string &)> G_TEST_LOG_FUN
This is connected to the logger.
Definition: fuzz.cpp:20
std::map< std::string_view, std::tuple< TypeTestOneInput, TypeInitialize, TypeHidden > > & FuzzTargets()
Definition: fuzz.cpp:22
void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden)
Definition: fuzz.cpp:28
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: fuzz.cpp:88
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition: fuzz.cpp:96
static TypeTestOneInput * g_test_one_input
Definition: fuzz.cpp:34
bool TypeHidden
Definition: fuzz.h:25
std::function< void(FuzzBufferType)> TypeTestOneInput
Definition: fuzz.h:23
std::function< void()> TypeInitialize
Definition: fuzz.h:24
fs::ofstream ofstream
Definition: fs.h:225
std::function< std::unique_ptr< Sock >(const CService &)> CreateSock
Socket factory.
Definition: netbase.cpp:529
std::vector< CNetAddr > WrappedGetAddrInfo(const std::string &name, bool allow_lookup)
Wrapper for getaddrinfo(3).
Definition: netbase.cpp:43
DNSLookupFn g_dns_lookup
Definition: netbase.cpp:85
void fuzz_target(FuzzBufferType buffer, const std::string &LIMIT_TO_MESSAGE_TYPE)
const char * name
Definition: rest.cpp:43