Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions centipede/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,36 @@ cc_library(
],
)

cc_library(
name = "engine_worker",
srcs = [
"engine_worker.cc",
"runner_utils.h",
],
hdrs = ["engine_worker_abi.h"],
deps = [
":execution_metadata",
":runner_request",
":runner_result",
":shared_memory_blob_sequence",
"@abseil-cpp//absl/base:nullability",
"@abseil-cpp//absl/random",
"@abseil-cpp//absl/random:bit_gen_ref",
"@com_google_fuzztest//centipede:engine_abi",
"@com_google_fuzztest//common:defs",
],
)

cc_library(
name = "engine_controller_with_subprocess",
srcs = ["engine_controller_with_subprocess.cc"],
hdrs = ["engine_controller_abi.h"],
deps = [
"@com_google_fuzztest//centipede:engine_abi",
"@com_google_fuzztest//fuzztest/internal:escaping",
],
)

# The runner library is special:
# * It must not be instrumented with asan, sancov, etc.
# * It must not have heavy dependencies, and ideally not at all.
Expand Down
39 changes: 9 additions & 30 deletions centipede/engine_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ typedef struct {
FuzzTestInputSinkCtx* ctx;

// Emits a test `input` to the engine. Engine would call
// `FuzzTestAdapter::FreeTestInput` on the emitted input after the engine is
// `FuzzTestAdapter::FreeInput` on the emitted input after the engine is
// done with it.
void (*Emit)(FuzzTestInputSinkCtx* ctx, FuzzTestInputHandle input);
} FuzzTestInputSink;
Expand Down Expand Up @@ -120,12 +120,13 @@ typedef struct {
uint8_t counter_bit_size;
} FuzzTestCoverageDomain;

typedef struct FuzzTestDomainRegistryCtx FuzzTestDomainRegistryCtx;
typedef struct FuzzTestCoverageDomainRegistryCtx
FuzzTestCoverageDomainRegistryCtx;
typedef struct {
FuzzTestDomainRegistryCtx* ctx;
FuzzTestCoverageDomainRegistryCtx* ctx;

// Registers a new coverage `domain`.
void (*Register)(FuzzTestDomainRegistryCtx* ctx,
void (*Register)(FuzzTestCoverageDomainRegistryCtx* ctx,
const FuzzTestCoverageDomain* domain);
} FuzzTestCoverageDomainRegistry;

Expand All @@ -134,11 +135,13 @@ typedef struct FuzzTestAdapter {
FuzzTestAdapterCtx* ctx;

// Registers coverage domains with `registry`.
// The coverage domains to register must be deterministic for the same test of
// the binary.
void (*GetCoverageDomains)(FuzzTestAdapterCtx* ctx,
const FuzzTestCoverageDomainRegistry* registry);

// [Optional] Emits any preset seed inputs of the test using `sink`.
// The output must be deterministic.
// The output must be deterministic for the same test of the binary.
void (*GetPresetSeedInputs)(FuzzTestAdapterCtx* ctx,
const FuzzTestInputSink* sink);

Expand Down Expand Up @@ -190,7 +193,7 @@ typedef struct FuzzTestAdapter {
FuzzTestInputHandle input);

// Drops the ownership of `input` from the engine.
void (*FreeTestInput)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle input);
void (*FreeInput)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle input);

// Drops the ownership of `ctx` from the engine.
void (*FreeCtx)(FuzzTestAdapterCtx* ctx);
Expand All @@ -216,30 +219,6 @@ typedef struct {
FuzzTestAdapter* adapter_out);
} FuzzTestAdapterManager;

typedef enum {
kFuzzTestWorkerSuccess = 0, // Test should finish with a success
kFuzzTestWorkerFailure, // Test should finish with a failure.
kFuzzTestWorkerNotRequired, // Test should continue with controller commands.
} FuzzTestWorkerStatus;

// Try to run as a FuzzTest worker with `manager` if needed.
FuzzTestWorkerStatus FuzzTestWorkerMaybeRun(
const FuzzTestAdapterManager* manager);

typedef enum {
kFuzzTestControllerSuccess = 0,
kFuzzTestControllerFailure,
} FuzzTestControllerStatus;

typedef struct {
const FuzzTestBytesView* views;
size_t count;
} FuzzTestBytesViews;

// Run the FuzzTest controller with `flags` and `manager`.
FuzzTestControllerStatus FuzzTestControllerRun(
const FuzzTestAdapterManager* manager, const FuzzTestBytesViews* flags);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
46 changes: 46 additions & 0 deletions centipede/engine_controller_abi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2026 The FuzzTest Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef FUZZTEST_CENTIPEDE_ENGINE_CONTROLLER_ABI_H_
#define FUZZTEST_CENTIPEDE_ENGINE_CONTROLLER_ABI_H_

// FuzzTest engine ABI.
//
// This header needs to be C-compatible.

#include "./centipede/engine_abi.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
kFuzzTestControllerSuccess = 0,
kFuzzTestControllerFailure,
} FuzzTestControllerStatus;

typedef struct {
const FuzzTestBytesView* views;
size_t count;
} FuzzTestBytesViews;

// Run the FuzzTest controller with `flags` and `manager`.
FuzzTestControllerStatus FuzzTestControllerRun(
const FuzzTestAdapterManager* manager, const FuzzTestBytesViews* flags);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // FUZZTEST_CENTIPEDE_ENGINE_CONTROLLER_ABI_H_
50 changes: 50 additions & 0 deletions centipede/engine_controller_with_subprocess.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2026 The FuzzTest Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sys/wait.h>

#include <cstdlib>
#include <cstring>
#include <string>

#include "./centipede/engine_abi.h"
#include "./centipede/engine_controller_abi.h"
#include "./fuzztest/internal/escaping.h"

using fuzztest::internal::ShellEscape;

FuzzTestControllerStatus FuzzTestControllerRun(
const FuzzTestAdapterManager* manager, const FuzzTestBytesViews* flags) {
// TODO(xinhaoyuan): Use the FuzzTest controller env var later.
static auto centipede_binary_path = []() -> const char* {
const char* env = std::getenv("FUZZTEST_CENTIPEDE_BINARY_PATH");
if (env == nullptr) return nullptr;
return strdup(env);
}();
if (centipede_binary_path == nullptr) {
return kFuzzTestControllerFailure;
}
std::string command;
command.append(ShellEscape(centipede_binary_path));
for (size_t flag_index = 0; flag_index < flags->count; ++flag_index) {
const auto& flag = flags->views[flag_index];
command.append(" ");
command.append(
ShellEscape({reinterpret_cast<const char*>(flag.data), flag.size}));
}
int ret = system(command.c_str());
if (ret == -1) return kFuzzTestControllerFailure;
return WIFEXITED(ret) && WEXITSTATUS(ret) == EXIT_SUCCESS
? kFuzzTestControllerSuccess
: kFuzzTestControllerFailure;
}
Loading
Loading