Skip to content

Commit 3e0e5fb

Browse files
yamilmoralescopybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 783788660
1 parent 0f82dad commit 3e0e5fb

File tree

11 files changed

+953
-555
lines changed

11 files changed

+953
-555
lines changed

centipede/BUILD

Lines changed: 40 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,41 @@ 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_sancov_object.cc",
1216+
"runner_utils.cc",
1217+
"sancov_shared.cc",
1218+
"shared_coverage_state.cc",
1219+
"@com_google_fuzztest//common:defs.h",
1220+
],
1221+
hdrs = [
1222+
"runner_dl_info.h",
1223+
"runner_interface.h",
1224+
"runner_sancov_object.h",
1225+
"runner_utils.h",
1226+
"sancov_interface.h",
1227+
"shared_coverage_state.h",
1228+
],
1229+
deps = [
1230+
":callstack",
1231+
":feature",
1232+
":foreach_nonzero",
1233+
":int_utils",
1234+
":mutation_input",
1235+
":pc_info",
1236+
":reverse_pc_table",
1237+
":runner_cmp_trace",
1238+
"@abseil-cpp//absl/base:core_headers",
1239+
"@abseil-cpp//absl/base:nullability",
1240+
"@abseil-cpp//absl/numeric:bits",
1241+
"@abseil-cpp//absl/types:span",
1242+
],
1243+
)
1244+
12051245
# Flags for :seed_corpus_maker.
12061246
cc_library(
12071247
name = "seed_corpus_maker_flags",

centipede/runner.cc

Lines changed: 122 additions & 131 deletions
Large diffs are not rendered by default.

centipede/runner.h

Lines changed: 1 addition & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,18 @@
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"
34-
#include "./centipede/concurrent_byteset.h"
3530
#include "./centipede/feature.h"
36-
#include "./centipede/hashed_ring_buffer.h"
3731
#include "./centipede/knobs.h"
38-
#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"
4232
#include "./centipede/runner_result.h"
43-
#include "./centipede/runner_sancov_object.h"
33+
#include "./centipede/shared_coverage_state.h"
4434

4535
namespace fuzztest::internal {
4636

@@ -54,79 +44,6 @@ class LockGuard {
5444
pthread_mutex_t &mu_;
5545
};
5646

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-
13047
// One global object of this type is created by the runner at start up.
13148
// All data members will be initialized to zero, unless they have initializers.
13249
// Accesses to the subobjects should be fast, so we are trying to avoid
@@ -144,79 +61,6 @@ struct GlobalRunnerState {
14461
GlobalRunnerState();
14562
~GlobalRunnerState();
14663

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-
22064
pthread_mutex_t execution_result_override_mu = PTHREAD_MUTEX_INITIALIZER;
22165
// If not nullptr, it points to a batch result with either zero or one
22266
// execution. When an execution result present, it will be passed as the
@@ -247,52 +91,11 @@ struct GlobalRunnerState {
24791
// Reclaims all TLSs in detached_tls_list and cleans up the list.
24892
void CleanUpDetachedTls();
24993

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-
264-
// State for SanitizerCoverage.
265-
// See https://clang.llvm.org/docs/SanitizerCoverage.html.
266-
SanCovObjectArray sancov_objects;
267-
// An arbitrarily large size.
268-
static constexpr size_t kDataFlowFeatureSetSize = 1 << 18;
269-
ConcurrentBitSet<kDataFlowFeatureSetSize> data_flow_feature_set{
270-
absl::kConstInit};
271-
27294
// Tracing CMP instructions, capture events from these domains:
27395
// kCMPEq, kCMPModDiff, kCMPHamming, kCMPModDiffLog, kCMPMsbEq.
27496
// See https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow.
275-
// An arbitrarily large size.
276-
static constexpr size_t kCmpFeatureSetSize = 1 << 18;
27797
// TODO(kcc): remove cmp_feature_set.
27898
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};
283-
284-
// We think that call stack produces rich signal, so we give a few bits to it.
285-
static constexpr size_t kCallStackFeatureSetSize = 1 << 24;
286-
ConcurrentBitSet<kCallStackFeatureSetSize> callstack_set{absl::kConstInit};
287-
288-
// kMaxNumPcs is the maximum number of instrumented PCs in the binary.
289-
// We can be generous here since the unused memory will not cost anything.
290-
// `pc_counter_set` is a static byte set supporting up to kMaxNumPcs PCs.
291-
static constexpr size_t kMaxNumPcs = 1 << 28;
292-
TwoLayerConcurrentByteSet<kMaxNumPcs> pc_counter_set{absl::kConstInit};
293-
// This is the actual number of PCs, aligned up to
294-
// pc_counter_set::kSizeMultiple, computed at startup.
295-
size_t actual_pc_counter_set_size_aligned;
29699

297100
// Initialized in CTOR from the __centipede_extra_features section.
298101
feature_t *user_defined_begin;
@@ -313,19 +116,9 @@ struct GlobalRunnerState {
313116
// * Use call stacks instead of paths (via unwinding or other
314117
// instrumentation).
315118

316-
// An arbitrarily large size.
317-
static constexpr size_t kPathBitSetSize = 1 << 25;
318-
// Observed paths. The total number of observed paths for --path_level=N
319-
// can be up to NumPCs**N.
320-
// So, we make the bitset very large, but it may still saturate.
321-
ConcurrentBitSet<kPathBitSetSize> path_feature_set{absl::kConstInit};
322-
323119
// Execution stats for the currently executed input.
324120
ExecutionResult::Stats stats;
325121

326-
// Used by trace_pc instrumentation. Populated if `pcs_file_path` flag is set.
327-
ReversePCTable reverse_pc_table;
328-
329122
// CentipedeRunnerMain() sets this to true.
330123
bool centipede_runner_main_executed = false;
331124

@@ -346,20 +139,9 @@ struct GlobalRunnerState {
346139

347140
// The Watchdog thread sets this to true.
348141
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};
359142
};
360143

361144
extern GlobalRunnerState state;
362-
extern __thread ThreadLocalRunnerState tls;
363145

364146
// Check for stack limit for the stack pointer `sp` in the current thread.
365147
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)