LCOV - code coverage report
Current view: top level - src/test/fuzz - fuzz.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 114 0
Test Date: 2024-08-28 04:44:32 Functions: 0.0 % 11 0
Branches: 0.0 % 136 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2009-present 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>
       9                 :             : #include <test/util/random.h>
      10                 :             : #include <test/util/setup_common.h>
      11                 :             : #include <util/check.h>
      12                 :             : #include <util/fs.h>
      13                 :             : #include <util/sock.h>
      14                 :             : #include <util/time.h>
      15                 :             : 
      16                 :             : #include <csignal>
      17                 :             : #include <cstdint>
      18                 :             : #include <cstdio>
      19                 :             : #include <cstdlib>
      20                 :             : #include <cstring>
      21                 :             : #include <exception>
      22                 :             : #include <fstream>
      23                 :             : #include <functional>
      24                 :             : #include <iostream>
      25                 :             : #include <map>
      26                 :             : #include <memory>
      27                 :             : #include <string>
      28                 :             : #include <tuple>
      29                 :             : #include <utility>
      30                 :             : #include <vector>
      31                 :             : 
      32                 :             : #if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && defined(__AFL_FUZZ_INIT)
      33                 :             : __AFL_FUZZ_INIT();
      34                 :             : #endif
      35                 :             : 
      36                 :             : const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
      37                 :             : 
      38                 :             : const std::function<std::string()> G_TEST_GET_FULL_NAME{};
      39                 :             : 
      40                 :             : /**
      41                 :             :  * A copy of the command line arguments that start with `--`.
      42                 :             :  * First `LLVMFuzzerInitialize()` is called, which saves the arguments to `g_args`.
      43                 :             :  * Later, depending on the fuzz test, `G_TEST_COMMAND_LINE_ARGUMENTS()` may be
      44                 :             :  * called by `BasicTestingSetup` constructor to fetch those arguments and store
      45                 :             :  * them in `BasicTestingSetup::m_node::args`.
      46                 :             :  */
      47                 :             : static std::vector<const char*> g_args;
      48                 :             : 
      49                 :           0 : static void SetArgs(int argc, char** argv) {
      50         [ #  # ]:           0 :     for (int i = 1; i < argc; ++i) {
      51                 :             :         // Only take into account arguments that start with `--`. The others are for the fuzz engine:
      52                 :             :         // `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5`
      53   [ #  #  #  #  :           0 :         if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') {
                   #  # ]
      54                 :           0 :             g_args.push_back(argv[i]);
      55                 :             :         }
      56                 :             :     }
      57                 :           0 : }
      58                 :             : 
      59                 :           0 : const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() {
      60                 :           0 :     return g_args;
      61                 :             : };
      62                 :             : 
      63                 :           0 : struct FuzzTarget {
      64                 :             :     const TypeTestOneInput test_one_input;
      65                 :             :     const FuzzTargetOptions opts;
      66                 :             : };
      67                 :             : 
      68                 :           0 : auto& FuzzTargets()
      69                 :             : {
      70   [ #  #  #  # ]:           0 :     static std::map<std::string_view, FuzzTarget> g_fuzz_targets;
      71                 :           0 :     return g_fuzz_targets;
      72                 :             : }
      73                 :             : 
      74                 :           0 : void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts)
      75                 :             : {
      76         [ #  # ]:           0 :     const auto [it, ins]{FuzzTargets().try_emplace(name, FuzzTarget /* temporary can be dropped after Apple-Clang-16 ? */ {std::move(target), std::move(opts)})};
      77                 :           0 :     Assert(ins);
      78                 :           0 : }
      79                 :             : 
      80                 :             : static std::string_view g_fuzz_target;
      81                 :             : static const TypeTestOneInput* g_test_one_input{nullptr};
      82                 :             : 
      83                 :             : 
      84                 :             : #if defined(__clang__) && defined(__linux__)
      85                 :             : extern "C" void __llvm_profile_reset_counters(void) __attribute__((weak));
      86                 :             : extern "C" void __gcov_reset(void) __attribute__((weak));
      87                 :             : 
      88                 :             : void ResetCoverageCounters()
      89                 :             : {
      90                 :             :     if (__llvm_profile_reset_counters) {
      91                 :             :         __llvm_profile_reset_counters();
      92                 :             :     }
      93                 :             : 
      94                 :             :     if (__gcov_reset) {
      95                 :             :         __gcov_reset();
      96                 :             :     }
      97                 :             : }
      98                 :             : #else
      99                 :           0 : void ResetCoverageCounters() {}
     100                 :             : #endif
     101                 :             : 
     102                 :             : 
     103                 :           0 : void initialize()
     104                 :             : {
     105                 :             :     // By default, make the RNG deterministic with a fixed seed. This will affect all
     106                 :             :     // randomness during the fuzz test, except:
     107                 :             :     // - GetStrongRandBytes(), which is used for the creation of private key material.
     108                 :             :     // - Creating a BasicTestingSetup or derived class will switch to a random seed.
     109                 :           0 :     SeedRandomForTest(SeedRand::ZEROS);
     110                 :             : 
     111                 :             :     // Terminate immediately if a fuzzing harness ever tries to create a socket.
     112                 :             :     // Individual tests can override this by pointing CreateSock to a mocked alternative.
     113                 :           0 :     CreateSock = [](int, int, int) -> std::unique_ptr<Sock> { std::terminate(); };
     114                 :             : 
     115                 :             :     // Terminate immediately if a fuzzing harness ever tries to perform a DNS lookup.
     116                 :           0 :     g_dns_lookup = [](const std::string& name, bool allow_lookup) {
     117         [ #  # ]:           0 :         if (allow_lookup) {
     118                 :           0 :             std::terminate();
     119                 :             :         }
     120                 :           0 :         return WrappedGetAddrInfo(name, false);
     121                 :           0 :     };
     122                 :             : 
     123                 :           0 :     bool should_exit{false};
     124         [ #  # ]:           0 :     if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
     125   [ #  #  #  # ]:           0 :         for (const auto& [name, t] : FuzzTargets()) {
     126         [ #  # ]:           0 :             if (t.opts.hidden) continue;
     127                 :           0 :             std::cout << name << std::endl;
     128                 :             :         }
     129                 :             :         should_exit = true;
     130                 :             :     }
     131         [ #  # ]:           0 :     if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) {
     132                 :           0 :         std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl;
     133                 :           0 :         std::ofstream out_stream{out_path, std::ios::binary};
     134   [ #  #  #  # ]:           0 :         for (const auto& [name, t] : FuzzTargets()) {
     135         [ #  # ]:           0 :             if (t.opts.hidden) continue;
     136   [ #  #  #  # ]:           0 :             out_stream << name << std::endl;
     137                 :             :         }
     138                 :           0 :         should_exit = true;
     139                 :           0 :     }
     140         [ #  # ]:           0 :     if (should_exit) {
     141                 :           0 :         std::exit(EXIT_SUCCESS);
     142                 :             :     }
     143         [ #  # ]:           0 :     if (const auto* env_fuzz{std::getenv("FUZZ")}) {
     144                 :             :         // To allow for easier fuzz executable binary modification,
     145   [ #  #  #  #  :           0 :         static std::string g_copy{env_fuzz}; // create copy to avoid compiler optimizations, and
                   #  # ]
     146                 :           0 :         g_fuzz_target = g_copy.c_str();      // strip string after the first null-char.
     147                 :             :     } else {
     148                 :           0 :         std::cerr << "Must select fuzz target with the FUZZ env var." << std::endl;
     149                 :           0 :         std::cerr << "Hint: Set the PRINT_ALL_FUZZ_TARGETS_AND_ABORT=1 env var to see all compiled targets." << std::endl;
     150                 :           0 :         std::exit(EXIT_FAILURE);
     151                 :             :     }
     152                 :           0 :     const auto it = FuzzTargets().find(g_fuzz_target);
     153         [ #  # ]:           0 :     if (it == FuzzTargets().end()) {
     154                 :           0 :         std::cerr << "No fuzz target compiled for " << g_fuzz_target << "." << std::endl;
     155                 :           0 :         std::exit(EXIT_FAILURE);
     156                 :             :     }
     157                 :           0 :     Assert(!g_test_one_input);
     158                 :           0 :     g_test_one_input = &it->second.test_one_input;
     159                 :           0 :     it->second.opts.init();
     160                 :             : 
     161                 :           0 :     ResetCoverageCounters();
     162                 :           0 : }
     163                 :             : 
     164                 :             : #if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
     165                 :           0 : static bool read_stdin(std::vector<uint8_t>& data)
     166                 :             : {
     167                 :           0 :     std::istream::char_type buffer[1024];
     168                 :           0 :     std::streamsize length;
     169         [ #  # ]:           0 :     while ((std::cin.read(buffer, 1024), length = std::cin.gcount()) > 0) {
     170                 :           0 :         data.insert(data.end(), buffer, buffer + length);
     171                 :             :     }
     172                 :           0 :     return length == 0;
     173                 :             : }
     174                 :             : #endif
     175                 :             : 
     176                 :             : #if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && !defined(__AFL_LOOP)
     177                 :           0 : static bool read_file(fs::path p, std::vector<uint8_t>& data)
     178                 :             : {
     179                 :           0 :     uint8_t buffer[1024];
     180                 :           0 :     FILE* f = fsbridge::fopen(p, "rb");
     181         [ #  # ]:           0 :     if (f == nullptr) return false;
     182                 :           0 :     do {
     183                 :           0 :         const size_t length = fread(buffer, sizeof(uint8_t), sizeof(buffer), f);
     184         [ #  # ]:           0 :         if (ferror(f)) return false;
     185                 :           0 :         data.insert(data.end(), buffer, buffer + length);
     186         [ #  # ]:           0 :     } while (!feof(f));
     187                 :           0 :     fclose(f);
     188                 :           0 :     return true;
     189                 :             : }
     190                 :             : #endif
     191                 :             : 
     192                 :             : #if defined(PROVIDE_FUZZ_MAIN_FUNCTION) && !defined(__AFL_LOOP)
     193                 :             : static fs::path g_input_path;
     194                 :           0 : void signal_handler(int signal)
     195                 :             : {
     196         [ #  # ]:           0 :     if (signal == SIGABRT) {
     197                 :           0 :         std::cerr << "Error processing input " << g_input_path << std::endl;
     198                 :             :     } else {
     199                 :           0 :         std::cerr << "Unexpected signal " << signal << " received\n";
     200                 :             :     }
     201                 :           0 :     std::_Exit(EXIT_FAILURE);
     202                 :             : }
     203                 :             : #endif
     204                 :             : 
     205                 :             : // This function is used by libFuzzer
     206                 :           0 : extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
     207                 :             : {
     208   [ #  #  #  #  :           0 :     static const auto& test_one_input = *Assert(g_test_one_input);
                   #  # ]
     209                 :           0 :     test_one_input({data, size});
     210                 :           0 :     return 0;
     211                 :             : }
     212                 :             : 
     213                 :             : // This function is used by libFuzzer
     214                 :           0 : extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
     215                 :             : {
     216                 :           0 :     SetArgs(*argc, *argv);
     217                 :           0 :     initialize();
     218                 :           0 :     return 0;
     219                 :             : }
     220                 :             : 
     221                 :             : #if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
     222                 :           0 : int main(int argc, char** argv)
     223                 :             : {
     224                 :           0 :     initialize();
     225   [ #  #  #  #  :           0 :     static const auto& test_one_input = *Assert(g_test_one_input);
                   #  # ]
     226                 :             : #ifdef __AFL_LOOP
     227                 :             :     // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
     228                 :             :     // See fuzzing.md for details.
     229                 :             :     const uint8_t* buffer = __AFL_FUZZ_TESTCASE_BUF;
     230                 :             :     while (__AFL_LOOP(100000)) {
     231                 :             :         size_t buffer_len = __AFL_FUZZ_TESTCASE_LEN;
     232                 :             :         test_one_input({buffer, buffer_len});
     233                 :             :     }
     234                 :             : #else
     235                 :           0 :     std::vector<uint8_t> buffer;
     236         [ #  # ]:           0 :     if (argc <= 1) {
     237   [ #  #  #  # ]:           0 :         if (!read_stdin(buffer)) {
     238                 :             :             return 0;
     239                 :             :         }
     240         [ #  # ]:           0 :         test_one_input(buffer);
     241                 :             :         return 0;
     242                 :             :     }
     243                 :           0 :     std::signal(SIGABRT, signal_handler);
     244                 :           0 :     const auto start_time{Now<SteadySeconds>()};
     245                 :           0 :     int tested = 0;
     246         [ #  # ]:           0 :     for (int i = 1; i < argc; ++i) {
     247         [ #  # ]:           0 :         fs::path input_path(*(argv + i));
     248   [ #  #  #  # ]:           0 :         if (fs::is_directory(input_path)) {
     249   [ #  #  #  #  :           0 :             for (fs::directory_iterator it(input_path); it != fs::directory_iterator(); ++it) {
                   #  # ]
     250   [ #  #  #  # ]:           0 :                 if (!fs::is_regular_file(it->path())) continue;
     251         [ #  # ]:           0 :                 g_input_path = it->path();
     252   [ #  #  #  #  :           0 :                 Assert(read_file(it->path(), buffer));
                   #  # ]
     253         [ #  # ]:           0 :                 test_one_input(buffer);
     254                 :           0 :                 ++tested;
     255   [ #  #  #  # ]:           0 :                 buffer.clear();
     256                 :           0 :             }
     257                 :             :         } else {
     258         [ #  # ]:           0 :             g_input_path = input_path;
     259   [ #  #  #  #  :           0 :             Assert(read_file(input_path, buffer));
                   #  # ]
     260         [ #  # ]:           0 :             test_one_input(buffer);
     261                 :           0 :             ++tested;
     262         [ #  # ]:           0 :             buffer.clear();
     263                 :             :         }
     264                 :           0 :     }
     265                 :           0 :     const auto end_time{Now<SteadySeconds>()};
     266   [ #  #  #  #  :           0 :     std::cout << g_fuzz_target << ": succeeded against " << tested << " files in " << count_seconds(end_time - start_time) << "s." << std::endl;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     267                 :             : #endif
     268                 :             :     return 0;
     269                 :           0 : }
     270                 :             : #endif
        

Generated by: LCOV version 2.0-1