/proc/self/cwd/test/fuzz/fuzz_runner.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "test/fuzz/fuzz_runner.h" |
2 | | |
3 | | #include <cstdlib> |
4 | | |
5 | | #include "source/common/common/thread.h" |
6 | | #include "source/common/common/utility.h" |
7 | | #include "source/common/event/libevent.h" |
8 | | #include "source/common/http/http2/codec_impl.h" |
9 | | #include "source/exe/process_wide.h" |
10 | | |
11 | | #include "test/test_common/environment.h" |
12 | | |
13 | | #include "absl/log/globals.h" |
14 | | #include "gmock/gmock.h" |
15 | | |
16 | | namespace Envoy { |
17 | | namespace Fuzz { |
18 | | |
19 | | spdlog::level::level_enum Runner::log_level_; |
20 | | |
21 | | uint32_t PerTestEnvironment::test_num_; |
22 | | |
23 | | PerTestEnvironment::PerTestEnvironment() |
24 | | : per_test_num_(test_num_++), |
25 | | test_tmpdir_(TestEnvironment::temporaryPath(fmt::format("fuzz_{}", per_test_num_))), |
26 | 2.84k | test_id_(std::to_string(HashUtil::xxHash64(test_tmpdir_))) { |
27 | 2.84k | TestEnvironment::createPath(test_tmpdir_); |
28 | 2.84k | } |
29 | | |
30 | 2.84k | PerTestEnvironment::~PerTestEnvironment() { TestEnvironment::removePath(test_tmpdir_); } |
31 | | |
32 | 126 | void Runner::setupEnvironment(int argc, char** argv, spdlog::level::level_enum default_log_level) { |
33 | | // We hold on to process_wide to provide RAII cleanup of process-wide |
34 | | // state. |
35 | 126 | ProcessWide process_wide; |
36 | 126 | TestEnvironment::initializeOptions(argc, argv); |
37 | | |
38 | 126 | const auto environment_log_level = TestEnvironment::getOptions().logLevel(); |
39 | | // We only override the default log level if it looks like we're debugging; |
40 | | // otherwise the default environment log level might override the default and |
41 | | // spew too much when running under a fuzz engine. |
42 | 126 | log_level_ = |
43 | 126 | environment_log_level <= spdlog::level::debug ? environment_log_level : default_log_level; |
44 | | // This needs to work in both the Envoy test shim and oss-fuzz build environments, so we can't |
45 | | // allocate in main.cc. Instead, just create these non-PODs to live forever, since we don't get a |
46 | | // shutdown hook (see |
47 | | // https://github.com/llvm-mirror/compiler-rt/blob/master/lib/fuzzer/FuzzerInterface.h). |
48 | 126 | static auto* lock = new Thread::MutexBasicLockable(); |
49 | 126 | static auto* logging_context = |
50 | 126 | new Logger::Context(log_level_, TestEnvironment::getOptions().logFormat(), *lock, false); |
51 | 126 | UNREFERENCED_PARAMETER(logging_context); |
52 | | |
53 | | // Suppress all libprotobuf non-fatal logging as long as this object exists. |
54 | | // For fuzzing, this prevents logging when parsing text-format protos fails, |
55 | | // deprecated fields are used, etc. |
56 | 126 | if (log_level_ > spdlog::level::debug) { |
57 | 126 | absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfinity); |
58 | 126 | } |
59 | 126 | } |
60 | | |
61 | | using Hooks = std::vector<std::function<void()>>; |
62 | | static Hooks* cleanup_hooks = nullptr; |
63 | | |
64 | 8 | void addCleanupHook(std::function<void()> cleanup) { |
65 | 8 | if (cleanup_hooks == nullptr) { |
66 | 4 | cleanup_hooks = new Hooks; |
67 | 4 | } |
68 | 8 | cleanup_hooks->push_back(cleanup); |
69 | 8 | } |
70 | | |
71 | 126 | void runCleanupHooks() { |
72 | 126 | if (cleanup_hooks != nullptr) { |
73 | | // Run hooks in reverse order from how they were added. |
74 | 12 | for (auto iter = cleanup_hooks->rbegin(), end = cleanup_hooks->rend(); iter != end; ++iter) { |
75 | 8 | (*iter)(); |
76 | 8 | } |
77 | 4 | delete cleanup_hooks; |
78 | 4 | cleanup_hooks = nullptr; |
79 | 4 | } |
80 | 126 | } |
81 | | |
82 | | } // namespace Fuzz |
83 | | } // namespace Envoy |
84 | | |
85 | | // LLVMFuzzerInitialize() is called by LibFuzzer once before fuzzing starts. |
86 | | // NOLINTNEXTLINE(readability-identifier-naming) |
87 | 126 | extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { |
88 | | // Before parsing gmock flags, set the default value of flag --gmock_verbose to "error". |
89 | | // This suppresses logs from NiceMock objects, which can be noisy and provide little value. |
90 | 126 | testing::GMOCK_FLAG(verbose) = "error"; |
91 | 126 | testing::InitGoogleMock(argc, *argv); |
92 | 126 | Envoy::Fuzz::Runner::setupEnvironment(1, *argv, spdlog::level::critical); |
93 | 126 | atexit(Envoy::Fuzz::runCleanupHooks); |
94 | 126 | return 0; |
95 | 126 | } |