Skip to content

Commit e91ddf2

Browse files
yamilmoralescopybara-github
authored andcommitted
Implement sancov runtime API to be able to emit features for other frameworks, and add a new interface to the dispatcher for exposed feature compatibility.
PiperOrigin-RevId: 796996087
1 parent c086c98 commit e91ddf2

File tree

7 files changed

+131
-20
lines changed

7 files changed

+131
-20
lines changed

centipede/BUILD

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,21 +1000,22 @@ cc_library(
10001000
# e.g. feature.cc. These files are compiled by the engine and the runner
10011001
# separately, with different compiler flags.
10021002
RUNNER_SOURCES_NO_MAIN = [
1003-
"sancov_state.cc",
1004-
"sancov_state.h",
10051003
"pc_info.h",
10061004
"reverse_pc_table.h",
10071005
"runner.cc",
10081006
"runner.h",
1009-
"runner_dl_info.h",
10101007
"runner_dl_info.cc",
1011-
"sancov_object_array.h",
1012-
"sancov_object_array.cc",
1013-
"runner_utils.h",
1014-
"runner_utils.cc",
1015-
"sancov_interceptors.cc",
1008+
"runner_dl_info.h",
10161009
"runner_interface.h",
1010+
"runner_utils.cc",
1011+
"runner_utils.h",
10171012
"sancov_callbacks.cc",
1013+
"sancov_interceptors.cc",
1014+
"sancov_object_array.cc",
1015+
"sancov_object_array.h",
1016+
"sancov_runtime.h",
1017+
"sancov_state.cc",
1018+
"sancov_state.h",
10181019
"@com_google_fuzztest//common:defs.h",
10191020
]
10201021

@@ -1194,10 +1195,11 @@ cc_library(
11941195
"sancov_object_array.cc",
11951196
"sancov_object_array.h",
11961197
"sancov_state.cc",
1198+
"sancov_state.h",
11971199
"@com_google_fuzztest//common:defs.h",
11981200
],
11991201
hdrs = [
1200-
"sancov_state.h",
1202+
"sancov_runtime.h",
12011203
],
12021204
copts = DISABLE_SANCOV_COPTS,
12031205
deps = [

centipede/dispatcher.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,20 @@ void FuzzTestDispatcherEmitFeedbackAs32BitFeatures(const uint32_t* features,
554554
"failed to write feedback");
555555
}
556556

557+
void FuzzTestDispatcherEmitFeedbackAsRawFeatures(const uint64_t* features,
558+
size_t num_features) {
559+
DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestExecute &&
560+
in_test_callback,
561+
"must be called inside test callback of executing");
562+
DispatcherCheck(num_features > 0 && features != nullptr,
563+
"feature array must be non-empty with a valid pointer");
564+
auto* output = GetOutputsBlobSequence();
565+
DispatcherCheck(output != nullptr, "outputs blob sequence must exist");
566+
DispatcherCheck(
567+
BatchResult::WriteOneFeatureVec(features, num_features, *output),
568+
"failed to write feedback");
569+
}
570+
557571
void FuzzTestDispatcherEmitExecutionMetadata(const void* metadata,
558572
size_t size) {
559573
DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestExecute &&

centipede/dispatcher.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ void FuzzTestDispatcherEmitSeed(const void* data, size_t size);
9595
// nullptr and `size > 0` must hold.
9696
void FuzzTestDispatcherEmitMutant(const void* data, size_t size);
9797

98+
// TODO: b/437901326 - Unify the feedback emission interfaces.
99+
98100
// Emits coverage feedback for the current input as an array of 32-bit features.
99101
//
100102
// For each 32-bit feature, the bit [31] is ignored; the 4 bits [30-27]
@@ -105,6 +107,14 @@ void FuzzTestDispatcherEmitMutant(const void* data, size_t size);
105107
// and `num_features > 0` must hold.
106108
void FuzzTestDispatcherEmitFeedbackAs32BitFeatures(const uint32_t* features,
107109
size_t num_features);
110+
111+
// Must only pass here the "raw" features exposed by the sancov runtime.
112+
//
113+
// Must be called from the `execute` callback. `features` must not be nullptr
114+
// and `num_features > 0` must hold.
115+
void FuzzTestDispatcherEmitFeedbackAsRawFeatures(const uint64_t* features,
116+
size_t num_features);
117+
108118
// Emits metadata of the current input as raw bytes. Must be called from
109119
// the `execute` callback.
110120
void FuzzTestDispatcherEmitExecutionMetadata(const void* metadata, size_t size);

centipede/runner.cc

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "./centipede/runner_request.h"
5858
#include "./centipede/runner_result.h"
5959
#include "./centipede/runner_utils.h"
60+
#include "./centipede/sancov_runtime.h"
6061
#include "./centipede/sancov_state.h"
6162
#include "./centipede/shared_memory_blob_sequence.h"
6263
#include "./common/defs.h"
@@ -395,10 +396,11 @@ static void ReadOneInputExecuteItAndDumpCoverage(const char *input_path,
395396
input_path);
396397
FILE *features_file = fopen(features_file_path, "w");
397398
PrintErrorAndExitIf(features_file == nullptr, "can't open coverage file");
398-
// TODO(yamilmorales): Hide the raw sancov state objects and expose
399-
// interface functions instead.
400-
WriteFeaturesToFile(features_file, sancov_state->g_features.data(),
401-
sancov_state->g_features.size());
399+
400+
const SanCovRuntimeRawFeatureParts sancov_features =
401+
SanCovRuntimeGetFeatures();
402+
WriteFeaturesToFile(features_file, sancov_features.features,
403+
sancov_features.num_features);
402404
fclose(features_file);
403405
}
404406

@@ -408,13 +410,15 @@ static bool StartSendingOutputsToEngine(BlobSequence &outputs_blobseq) {
408410
return BatchResult::WriteInputBegin(outputs_blobseq);
409411
}
410412

411-
// Copy all the `g_features` to `data` with given `capacity` in bytes.
412-
// Returns the byte size of `g_features`.
413+
// Copy all the sancov features to `data` with given `capacity` in bytes.
414+
// Returns the byte size of sancov features.
413415
static size_t CopyFeatures(uint8_t *data, size_t capacity) {
416+
const SanCovRuntimeRawFeatureParts sancov_features =
417+
SanCovRuntimeGetFeatures();
414418
const size_t features_len_in_bytes =
415-
sancov_state->g_features.size() * sizeof(feature_t);
419+
sancov_features.num_features * sizeof(feature_t);
416420
if (features_len_in_bytes > capacity) return 0;
417-
memcpy(data, sancov_state->g_features.data(), features_len_in_bytes);
421+
memcpy(data, sancov_features.features, features_len_in_bytes);
418422
return features_len_in_bytes;
419423
}
420424

@@ -441,9 +445,11 @@ static bool FinishSendingOutputsToEngine(BlobSequence &outputs_blobseq) {
441445
}
442446
}
443447

448+
const SanCovRuntimeRawFeatureParts sancov_features =
449+
SanCovRuntimeGetFeatures();
444450
// Copy features to shared memory.
445-
if (!BatchResult::WriteOneFeatureVec(sancov_state->g_features.data(),
446-
sancov_state->g_features.size(),
451+
if (!BatchResult::WriteOneFeatureVec(sancov_features.features,
452+
sancov_features.num_features,
447453
outputs_blobseq)) {
448454
return false;
449455
}
@@ -749,7 +755,6 @@ GlobalRunnerState::GlobalRunnerState() {
749755

750756
// TODO(kcc): move some code from CentipedeRunnerMain() here so that it works
751757
// even if CentipedeRunnerMain() is not called.
752-
tls.OnThreadStart();
753758
state->StartWatchdogThread();
754759

755760
SetLimits();

centipede/sancov_runtime.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2025 The Centipede Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef FUZZTEST_CENTIPEDE_SANCOV_RUNTIME_H_
16+
#define FUZZTEST_CENTIPEDE_SANCOV_RUNTIME_H_
17+
18+
// Sancov runtime interface.
19+
//
20+
// This header needs to be C compatible.
21+
22+
#include <stdbool.h> // NOLINT
23+
#include <stddef.h>
24+
#include <stdint.h>
25+
26+
#ifdef __cplusplus
27+
extern "C" {
28+
#endif
29+
30+
struct SanCovRuntimeRawFeatureParts {
31+
const uint64_t* features;
32+
size_t num_features;
33+
};
34+
35+
// Clears coverage data accumulated so far from sancov callbacks and/or
36+
// interceptors.
37+
//
38+
// Will always clear the thread-local data updated during execution, and if
39+
// `full_clear==true` will clear all accumulated coverage data.
40+
void SanCovRuntimeClearCoverage(bool full_clear);
41+
42+
// Post-processes all coverage data, putting it all into an array of features,
43+
// and returning a ptr and the length of this array.
44+
//
45+
// Will return a valid `features` pointer to a 64-bit element array of length
46+
// `num_features`: This feature array is initialized at process startup, and
47+
// its data (belonging to a global state) will remain valid for the duration of
48+
// the process.
49+
//
50+
// If `reject_input==true`, then it will simply empty the feature array.
51+
struct SanCovRuntimeRawFeatureParts SanCovRuntimeGetCoverage(bool reject_input);
52+
53+
#ifdef __cplusplus
54+
} // extern "C"
55+
#endif
56+
57+
#endif // FUZZTEST_CENTIPEDE_SANCOV_RUNTIME_H_

centipede/sancov_state.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "./centipede/pc_info.h"
3232
#include "./centipede/runner_dl_info.h"
3333
#include "./centipede/runner_utils.h"
34+
#include "./centipede/sancov_runtime.h"
3435

3536
__attribute__((weak)) extern fuzztest::internal::feature_t
3637
__start___centipede_extra_features;
@@ -226,6 +227,7 @@ static void DumpDsoTable(const char *absl_nonnull output_path) {
226227
}
227228

228229
SancovState::SancovState() {
230+
tls.OnThreadStart();
229231
// Compute main_object.
230232
main_object = GetDlInfo(flag_helper.GetStringFlag(":dl_path_suffix="));
231233
if (!sancov_state->main_object.IsSet()) {
@@ -484,6 +486,11 @@ bool CopyCmpTracesToMetadata(ExecutionMetadata *metadata) {
484486
return true;
485487
}
486488

489+
SanCovRuntimeRawFeatureParts SanCovRuntimeGetFeatures() {
490+
return {fuzztest::internal::sancov_state->g_features.data(),
491+
fuzztest::internal::sancov_state->g_features.size()};
492+
}
493+
487494
} // namespace fuzztest::internal
488495

489496
// Can be overridden to not depend explicitly on CENTIPEDE_RUNNER_FLAGS.
@@ -492,3 +499,15 @@ extern "C" __attribute__((weak)) const char *absl_nullable GetSancovFlags() {
492499
return strdup(sancov_flags_env);
493500
return nullptr;
494501
}
502+
503+
void SanCovRuntimeClearCoverage(bool full_clear) {
504+
fuzztest::internal::CleanUpSancovTls();
505+
fuzztest::internal::PrepareSancov(full_clear);
506+
}
507+
508+
struct SanCovRuntimeRawFeatureParts SanCovRuntimeGetCoverage(
509+
bool reject_input) {
510+
fuzztest::internal::PostProcessSancov(reject_input);
511+
512+
return fuzztest::internal::SanCovRuntimeGetFeatures();
513+
}

centipede/sancov_state.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "./centipede/runner_dl_info.h"
4141
#include "./centipede/runner_utils.h"
4242
#include "./centipede/sancov_object_array.h"
43+
#include "./centipede/sancov_runtime.h"
4344

4445
extern "C" const char *absl_nullable GetSancovFlags();
4546

@@ -287,6 +288,9 @@ void PostProcessSancov(bool reject_input = false);
287288

288289
void MaybeAddFeature(feature_t feature);
289290

291+
// Returns a pointer to `g_features` and its length.
292+
SanCovRuntimeRawFeatureParts SanCovRuntimeGetFeatures();
293+
290294
// Check for stack limit for the stack pointer `sp` in the current thread.
291295
__attribute__((weak)) void CheckStackLimit(uintptr_t sp);
292296

0 commit comments

Comments
 (0)