Coverage Report

Created: 2023-11-12 09:30

/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
}