Skip to content

Commit 6ef86bd

Browse files
yamilmoralescopybara-github
authored andcommitted
Refactor coverage out of GlobalRunnerState with the purpose of sharing it with the Rust FuzzTest framework for emitting features.
PiperOrigin-RevId: 783336614
1 parent 0f82dad commit 6ef86bd

File tree

11 files changed

+889
-503
lines changed

11 files changed

+889
-503
lines changed

centipede/BUILD

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,11 @@ cc_library(
10241024
# e.g. feature.cc. These files are compiled by the engine and the runner
10251025
# separately, with different compiler flags.
10261026
RUNNER_SOURCES_NO_MAIN = [
1027+
"sancov_cpp.cc",
1028+
"shared_coverage_state.cc",
1029+
"shared_coverage_state.h",
1030+
"sancov_interface.h",
1031+
"sancov_shared.cc",
10271032
"byte_array_mutator.cc",
10281033
"byte_array_mutator.h",
10291034
"callstack.h",
@@ -1202,6 +1207,37 @@ cc_library(
12021207
],
12031208
)
12041209

1210+
cc_library(
1211+
name = "shared_coverage",
1212+
srcs = [
1213+
"runner_dl_info.cc",
1214+
"runner_sancov.cc",
1215+
"runner_utils.cc",
1216+
"sancov_shared.cc",
1217+
"shared_coverage_state.cc",
1218+
"@com_google_fuzztest//common:defs.h",
1219+
],
1220+
hdrs = [
1221+
"runner_dl_info.h",
1222+
"runner_interface.h",
1223+
"runner_utils.h",
1224+
"sancov_interface.h",
1225+
"shared_coverage_state.h",
1226+
],
1227+
deps = [
1228+
":callstack",
1229+
":feature",
1230+
":int_utils",
1231+
":mutation_input",
1232+
":pc_info",
1233+
":runner_cmp_trace",
1234+
"@abseil-cpp//absl/base:core_headers",
1235+
"@abseil-cpp//absl/base:nullability",
1236+
"@abseil-cpp//absl/numeric:bits",
1237+
"@abseil-cpp//absl/types:span",
1238+
],
1239+
)
1240+
12051241
# Flags for :seed_corpus_maker.
12061242
cc_library(
12071243
name = "seed_corpus_maker_flags",

centipede/runner.cc

Lines changed: 100 additions & 113 deletions
Large diffs are not rendered by default.

centipede/runner.h

Lines changed: 1 addition & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,21 @@
1919
#include <string.h>
2020
#include <time.h>
2121

22-
#include <algorithm>
2322
#include <atomic>
2423
#include <cstddef>
2524
#include <cstdint>
2625
#include <cstdlib>
2726

2827
#include "absl/base/const_init.h"
29-
#include "absl/base/nullability.h"
30-
#include "absl/numeric/bits.h"
3128
#include "./centipede/byte_array_mutator.h"
32-
#include "./centipede/callstack.h"
3329
#include "./centipede/concurrent_bitset.h"
3430
#include "./centipede/concurrent_byteset.h"
3531
#include "./centipede/feature.h"
36-
#include "./centipede/hashed_ring_buffer.h"
3732
#include "./centipede/knobs.h"
3833
#include "./centipede/reverse_pc_table.h"
39-
#include "./centipede/runner_cmp_trace.h"
40-
#include "./centipede/runner_dl_info.h"
41-
#include "./centipede/runner_interface.h"
4234
#include "./centipede/runner_result.h"
4335
#include "./centipede/runner_sancov_object.h"
36+
#include "./centipede/shared_coverage_state.h"
4437

4538
namespace fuzztest::internal {
4639

@@ -54,79 +47,6 @@ class LockGuard {
5447
pthread_mutex_t &mu_;
5548
};
5649

57-
// Flags derived from CENTIPEDE_RUNNER_FLAGS.
58-
// Flags used in instrumentation callbacks are bit-packed for efficiency.
59-
struct RunTimeFlags {
60-
uint64_t path_level : 8;
61-
uint64_t use_pc_features : 1;
62-
uint64_t use_dataflow_features : 1;
63-
uint64_t use_cmp_features : 1;
64-
uint64_t callstack_level : 8;
65-
uint64_t use_counter_features : 1;
66-
uint64_t use_auto_dictionary : 1;
67-
std::atomic<uint64_t> timeout_per_input;
68-
uint64_t timeout_per_batch;
69-
std::atomic<uint64_t> stack_limit_kb;
70-
std::atomic<uint64_t> rss_limit_mb;
71-
uint64_t crossover_level;
72-
uint64_t skip_seen_features : 1;
73-
uint64_t ignore_timeout_reports : 1;
74-
uint64_t max_len;
75-
};
76-
77-
// One such object is created in runner's TLS.
78-
// There is no CTOR, since we don't want to use the brittle and lazy TLS CTORs.
79-
// All data members are zero-initialized during thread creation.
80-
struct ThreadLocalRunnerState {
81-
// Traces the memory comparison of `n` bytes at `s1` and `s2` called at
82-
// `caller_pc` with `is_equal` indicating whether the two memory regions have
83-
// equal contents. May add cmp features and auto-dictionary entries if
84-
// enabled.
85-
void TraceMemCmp(uintptr_t caller_pc, const uint8_t *s1, const uint8_t *s2,
86-
size_t n, bool is_equal);
87-
88-
// Intrusive doubly-linked list of TLS objects.
89-
// Guarded by state.tls_list_mu.
90-
ThreadLocalRunnerState *next, *prev;
91-
92-
// The pthread_create() interceptor calls OnThreadStart() before the thread
93-
// callback. The main thread also calls OnThreadStart(). OnThreadStop() will
94-
// be called when thread termination is detected internally - see runner.cc.
95-
void OnThreadStart();
96-
void OnThreadStop();
97-
98-
// Whether OnThreadStart() is called on this thread. This is used as a proxy
99-
// of the readiness of the lower-level runtime.
100-
bool started;
101-
102-
// Paths are thread-local, so we maintain the current bounded path here.
103-
// We allow paths of up to 100, controlled at run-time via the "path_level".
104-
static constexpr uint64_t kBoundedPathLength = 100;
105-
HashedRingBuffer<kBoundedPathLength> path_ring_buffer;
106-
107-
// Value of SP in the top call frame of the thread, computed in OnThreadStart.
108-
uintptr_t top_frame_sp;
109-
// The lower bound of the stack region of this thread. 0 means unknown.
110-
uintptr_t stack_region_low;
111-
// Lowest observed value of SP.
112-
uintptr_t lowest_sp;
113-
114-
// The (imprecise) call stack is updated by the PC callback.
115-
CallStack<> call_stack;
116-
117-
// Cmp traces capture the arguments of CMP instructions, memcmp, etc.
118-
// We have dedicated traces for 2-, 4-, and 8-byte comparison, and
119-
// a catch-all `cmp_traceN` trace for memcmp, etc.
120-
CmpTrace<2, 64> cmp_trace2;
121-
CmpTrace<4, 64> cmp_trace4;
122-
CmpTrace<8, 64> cmp_trace8;
123-
CmpTrace<0, 64> cmp_traceN;
124-
125-
// Set this to true if the thread needs to be ignored in ForEachTLS.
126-
// It should be always false if the state is in the global detached_tls_list.
127-
bool ignore;
128-
};
129-
13050
// One global object of this type is created by the runner at start up.
13151
// All data members will be initialized to zero, unless they have initializers.
13252
// Accesses to the subobjects should be fast, so we are trying to avoid
@@ -144,79 +64,6 @@ struct GlobalRunnerState {
14464
GlobalRunnerState();
14565
~GlobalRunnerState();
14666

147-
// Runner reads flags from CentipedeGetRunnerFlags(). We don't use flags
148-
// passed via argv so that argv flags can be passed directly to
149-
// LLVMFuzzerInitialize, w/o filtering. The flags are separated with
150-
// ':' on both sides, i.e. like this: ":flag1:flag2:flag3=value3".
151-
// We do it this way to make the flag parsing code extremely simple. The
152-
// interface is private between Centipede and the runner and may change.
153-
//
154-
// Note that this field reflects the initial runner flags. But some
155-
// flags can change later (if wrapped with std::atomic).
156-
const char *centipede_runner_flags = CentipedeGetRunnerFlags();
157-
const char *arg1 = GetStringFlag(":arg1=");
158-
const char *arg2 = GetStringFlag(":arg2=");
159-
const char *arg3 = GetStringFlag(":arg3=");
160-
// The path to a file where the runner may write the description of failure.
161-
const char *failure_description_path =
162-
GetStringFlag(":failure_description_path=");
163-
164-
// Flags.
165-
RunTimeFlags run_time_flags = {
166-
/*path_level=*/std::min(ThreadLocalRunnerState::kBoundedPathLength,
167-
HasIntFlag(":path_level=", 0)),
168-
/*use_pc_features=*/HasFlag(":use_pc_features:"),
169-
/*use_dataflow_features=*/HasFlag(":use_dataflow_features:"),
170-
/*use_cmp_features=*/HasFlag(":use_cmp_features:"),
171-
/*callstack_level=*/HasIntFlag(":callstack_level=", 0),
172-
/*use_counter_features=*/HasFlag(":use_counter_features:"),
173-
/*use_auto_dictionary=*/HasFlag(":use_auto_dictionary:"),
174-
/*timeout_per_input=*/HasIntFlag(":timeout_per_input=", 0),
175-
/*timeout_per_batch=*/HasIntFlag(":timeout_per_batch=", 0),
176-
/*stack_limit_kb=*/HasIntFlag(":stack_limit_kb=", 0),
177-
/*rss_limit_mb=*/HasIntFlag(":rss_limit_mb=", 0),
178-
/*crossover_level=*/HasIntFlag(":crossover_level=", 50),
179-
/*skip_seen_features=*/HasFlag(":skip_seen_features:"),
180-
/*ignore_timeout_reports=*/HasFlag(":ignore_timeout_reports:"),
181-
/*max_len=*/HasIntFlag(":max_len=", 4000),
182-
};
183-
184-
// Returns true iff `flag` is present.
185-
// Typical usage: pass ":some_flag:", i.e. the flag name surrounded with ':'.
186-
// TODO(ussuri): Refactor `char *` into a `string_view`.
187-
bool HasFlag(const char *absl_nonnull flag) const {
188-
if (!centipede_runner_flags) return false;
189-
return strstr(centipede_runner_flags, flag) != nullptr;
190-
}
191-
192-
// If a flag=value pair is present, returns value,
193-
// otherwise returns `default_value`.
194-
// Typical usage: pass ":some_flag=".
195-
// TODO(ussuri): Refactor `char *` into a `string_view`.
196-
uint64_t HasIntFlag(const char *absl_nonnull flag,
197-
uint64_t default_value) const {
198-
if (!centipede_runner_flags) return default_value;
199-
const char *beg = strstr(centipede_runner_flags, flag);
200-
if (!beg) return default_value;
201-
return atoll(beg + strlen(flag)); // NOLINT: can't use strto64, etc.
202-
}
203-
204-
// If a :flag=value: pair is present returns value, otherwise returns nullptr.
205-
// The result is obtained by calling strndup, so make sure to save
206-
// it in `this` to avoid a leak.
207-
// Typical usage: pass ":some_flag=".
208-
// TODO(ussuri): Refactor `char *` into a `string_view`.
209-
const char *absl_nullable GetStringFlag(const char *absl_nonnull flag) const {
210-
if (!centipede_runner_flags) return nullptr;
211-
// Extract "value" from ":flag=value:" inside centipede_runner_flags.
212-
const char *beg = strstr(centipede_runner_flags, flag);
213-
if (!beg) return nullptr;
214-
const char *value_beg = beg + strlen(flag);
215-
const char *end = strstr(value_beg, ":");
216-
if (!end) return nullptr;
217-
return strndup(value_beg, end - value_beg);
218-
}
219-
22067
pthread_mutex_t execution_result_override_mu = PTHREAD_MUTEX_INITIALIZER;
22168
// If not nullptr, it points to a batch result with either zero or one
22269
// execution. When an execution result present, it will be passed as the
@@ -247,20 +94,6 @@ struct GlobalRunnerState {
24794
// Reclaims all TLSs in detached_tls_list and cleans up the list.
24895
void CleanUpDetachedTls();
24996

250-
// Computed by DlInfo().
251-
// Usually, the main object is the executable binary containing main()
252-
// and most of the executable code (we assume that the target is
253-
// built in mostly-static mode, i.e. -dynamic_mode=off).
254-
// When the `dl_path_suffix` runner flag is provided, the main_object refers
255-
// to the dynamic library (DSO) pointed to by this flag.
256-
//
257-
// Note: this runner currently does not support more than one instrumented
258-
// DSO in the process, i.e. you either instrument the main binary, or one DSO.
259-
// Supporting more than one DSO will require major changes,
260-
// major added complexity, and potentially cause slowdown.
261-
// There is currently no motivation for such a change.
262-
DlInfo main_object;
263-
26497
// State for SanitizerCoverage.
26598
// See https://clang.llvm.org/docs/SanitizerCoverage.html.
26699
SanCovObjectArray sancov_objects;
@@ -272,14 +105,8 @@ struct GlobalRunnerState {
272105
// Tracing CMP instructions, capture events from these domains:
273106
// kCMPEq, kCMPModDiff, kCMPHamming, kCMPModDiffLog, kCMPMsbEq.
274107
// See https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow.
275-
// An arbitrarily large size.
276-
static constexpr size_t kCmpFeatureSetSize = 1 << 18;
277108
// TODO(kcc): remove cmp_feature_set.
278109
ConcurrentBitSet<kCmpFeatureSetSize> cmp_feature_set{absl::kConstInit};
279-
ConcurrentBitSet<kCmpFeatureSetSize> cmp_eq_set{absl::kConstInit};
280-
ConcurrentBitSet<kCmpFeatureSetSize> cmp_moddiff_set{absl::kConstInit};
281-
ConcurrentBitSet<kCmpFeatureSetSize> cmp_hamming_set{absl::kConstInit};
282-
ConcurrentBitSet<kCmpFeatureSetSize> cmp_difflog_set{absl::kConstInit};
283110

284111
// We think that call stack produces rich signal, so we give a few bits to it.
285112
static constexpr size_t kCallStackFeatureSetSize = 1 << 24;
@@ -346,20 +173,9 @@ struct GlobalRunnerState {
346173

347174
// The Watchdog thread sets this to true.
348175
std::atomic<bool> watchdog_thread_started;
349-
350-
// An arbitrarily large size.
351-
static const size_t kMaxFeatures = 1 << 20;
352-
// FeatureArray used to accumulate features from all sources.
353-
FeatureArray<kMaxFeatures> g_features;
354-
355-
// Features that were seen before.
356-
static constexpr size_t kSeenFeatureSetSize =
357-
absl::bit_ceil(feature_domains::kLastDomain.end());
358-
ConcurrentBitSet<kSeenFeatureSetSize> seen_features{absl::kConstInit};
359176
};
360177

361178
extern GlobalRunnerState state;
362-
extern __thread ThreadLocalRunnerState tls;
363179

364180
// Check for stack limit for the stack pointer `sp` in the current thread.
365181
void CheckStackLimit(uintptr_t sp);

centipede/runner_interceptors.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include "absl/base/nullability.h"
2424
#include "absl/base/optimization.h"
25-
#include "./centipede/runner.h"
25+
#include "./centipede/shared_coverage_state.h"
2626

2727
using fuzztest::internal::tls;
2828

centipede/runner_interface.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <functional>
2323
#include <memory>
2424
#include <string>
25-
#include <string_view>
2625
#include <vector>
2726

2827
#include "absl/base/nullability.h"

0 commit comments

Comments
 (0)