No public description PiperOrigin-RevId: 918490230
diff --git a/centipede/BUILD b/centipede/BUILD index b01c22c..1000d7f 100644 --- a/centipede/BUILD +++ b/centipede/BUILD
@@ -1255,6 +1255,11 @@ ], ) +cc_library( + name = "engine_abi", + hdrs = ["engine_abi.h"], +) + sh_library( name = "test_fuzzing_util_sh", srcs = ["test_fuzzing_util.sh"],
diff --git a/centipede/engine_abi.h b/centipede/engine_abi.h new file mode 100644 index 0000000..43e81c7 --- /dev/null +++ b/centipede/engine_abi.h
@@ -0,0 +1,247 @@ +// 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_ABI_H_ +#define FUZZTEST_CENTIPEDE_ENGINE_ABI_H_ + +// FuzzTest engine ABI. +// +// This header needs to be C-compatible. + +#include <stddef.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Opaque handles for in-memory input objects used by the test, which +// may be serialized/deserialized by the engine. +typedef uintptr_t FuzzTestInputHandle; + +typedef struct { + const uint8_t* data; + size_t size; +} FuzzTestBytesView; + +// Sink for diagnostics during the setup and execution of the test +// methods. Methods in this sink are async-safe and thread-safe. +typedef struct FuzzTestDiagnosticSinkCtx FuzzTestDiagnosticSinkCtx; +typedef struct { + FuzzTestDiagnosticSinkCtx* ctx; + + // Emits an unrecoverable error with a human-readable `message`. Engine would + // propagate the error to the controller command when in the worker mode. + void (*EmitError)(FuzzTestDiagnosticSinkCtx* ctx, + const FuzzTestBytesView* message); + + // Emits a warning with a human-readable `message`. Engine would log + // the warning and continue gracefully when in the worker mode. + void (*EmitWarning)(FuzzTestDiagnosticSinkCtx* ctx, + const FuzzTestBytesView* message); + + // Emits a finding for running a test input within `Execute()` with a + // human-readable `description`, and `signature` for deduplication. + // + // Must not be called if the engine is not calling `Execute()`. If called + // multiple times within the same `Execute()` window, a random one would take + // effect. + void (*EmitFinding)(FuzzTestDiagnosticSinkCtx* ctx, + const FuzzTestBytesView* description, + const FuzzTestBytesView* signature); +} FuzzTestDiagnosticSink; + +// Sink for bytes data. +typedef struct FuzzTestBytesSinkCtx FuzzTestBytesSinkCtx; +typedef struct { + FuzzTestBytesSinkCtx* ctx; + + // Emits a byte buffer. Multiple emissions are concatenated. + void (*Emit)(FuzzTestBytesSinkCtx* ctx, const FuzzTestBytesView* view); +} FuzzTestBytesSink; + +// Sink for seed inputs. +typedef struct FuzzTestInputSinkCtx FuzzTestInputSinkCtx; +typedef struct { + FuzzTestInputSinkCtx* ctx; + + // Emits a test `input` to the engine. Engine would call + // `FuzzTestAdapter::FreeTestInput` on the emitted input after the engine is + // done with it. + void (*Emit)(FuzzTestInputSinkCtx* ctx, FuzzTestInputHandle input); +} FuzzTestInputSink; + +typedef struct { + const uint64_t* data; + size_t size; +} FuzzTestUint64sView; + +// Sink for execution feedback. +typedef struct FuzzTestFeedbackSinkCtx FuzzTestFeedbackSinkCtx; +typedef struct { + FuzzTestFeedbackSinkCtx* ctx; + + // Emits an array of coverage features captured from the execution + // inside `Execute` call. + // + // Each feature is a 64-bit unsigned integer with the following layout: + // + // - Bits 63..59: 5-bit domain ID of the feature. Each domain is a + // logically independent feature namespace registered in + // `FuzzTestAdapter::GetCoverageDomains`. + // - Bits 58..32: 27-bit feature ID within the domain. + // - Bits 31..0: 32-bit counter value of the feature. + // + // Multiple emissions are concatenated. + void (*EmitCoverageFeatures)(FuzzTestFeedbackSinkCtx* ctx, + const FuzzTestUint64sView* features); +} FuzzTestFeedbackSink; + +// Information of a coverage domain. +typedef struct { + // 5-bit domain ID. + uint8_t domain_id; + // Human-readable name of the domain for logging. + FuzzTestBytesView name; + // Number of bits used for the feature IDs in this domain, must be <= 27. + uint8_t feature_id_bit_size; + // Number of bits used for the counter values in this domain, must be <= 32. + uint8_t counter_bit_size; +} FuzzTestCoverageDomain; + +typedef struct FuzzTestDomainRegistryCtx FuzzTestDomainRegistryCtx; +typedef struct { + FuzzTestDomainRegistryCtx* ctx; + + // Registers a new coverage `domain`. + void (*Register)(FuzzTestDomainRegistryCtx* ctx, + const FuzzTestCoverageDomain* domain); +} FuzzTestCoverageDomainRegistry; + +typedef struct FuzzTestAdapterCtx FuzzTestAdapterCtx; +typedef struct FuzzTestAdapter { + FuzzTestAdapterCtx* ctx; + + // Registers coverage domains with `registry`. + void (*GetCoverageDomains)(FuzzTestAdapterCtx* ctx, + const FuzzTestCoverageDomainRegistry* registry); + + // [Optional] Emits any preset seed inputs of the test using `sink`. + // The output must be deterministic. + void (*GetPresetSeedInputs)(FuzzTestAdapterCtx* ctx, + const FuzzTestInputSink* sink); + + // Emits a randomly generated seed input using `sink`. + void (*GetRandomSeedInput)(FuzzTestAdapterCtx* ctx, + const FuzzTestInputSink* sink); + + // Mutates from `origin`, and emits the mutant using `sink`. `shrink` != 0 + // means to generate smaller mutant. + // + // It should not change the content/metadata of `origin`. + void (*Mutate)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle origin, + int shrink, const FuzzTestInputSink* sink); + + // [Optional] Performs cross-over mutation using `origin` and `other`, and + // emits the mutant using `sink`. + // + // It should not change the content/metadata of `origin` or `other`. + void (*CrossOver)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle origin, + FuzzTestInputHandle other, const FuzzTestInputSink* sink); + + // Executes `input` for testing and emits any feedback to `sink`. + // + // The `input` metadata may be updated by the adapter for further + // mutations. The `input` content, which affects the test behavior of + // `Execute()`, should not be changed. + void (*Execute)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle input, + const FuzzTestFeedbackSink* sink); + + // Serializes the test `input` content into bytes using `sink`. + void (*SerializeInputContent)(FuzzTestAdapterCtx* ctx, + FuzzTestInputHandle input, + const FuzzTestBytesSink* sink); + + // Deserializes the test `input` content from serialized `content` into + // a `FuzzTestInputHandle` using `sink`. + void (*DeserializeInputContent)(FuzzTestAdapterCtx* ctx, + const FuzzTestBytesView* content, + const FuzzTestInputSink* sink); + + // [Optional] Serializes the test `input` metadata into bytes using `sink`. + void (*SerializeInputMetadata)(FuzzTestAdapterCtx* ctx, + FuzzTestInputHandle input, + const FuzzTestBytesSink* sink); + + // [Optional] Updates the test `input` metadata from serialized `metadata`. + void (*UpdateInputMetadata)(FuzzTestAdapterCtx* ctx, + const FuzzTestBytesView* metadata, + FuzzTestInputHandle input); + + // Drops the ownership of `input` from the engine. + void (*FreeTestInput)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle input); + + // Drops the ownership of `ctx` from the engine. + void (*FreeCtx)(FuzzTestAdapterCtx* ctx); +} FuzzTestAdapter; + +typedef struct FuzzTestAdapterManagerCtx FuzzTestAdapterManagerCtx; +typedef struct { + FuzzTestAdapterManagerCtx* ctx; + + // [Optional] Emits the ID for the current binary. + void (*GetBinaryId)(FuzzTestAdapterManagerCtx* ctx, + const FuzzTestBytesSink* sink); + + // Emits the test name. + void (*GetTestName)(FuzzTestAdapterManagerCtx* ctx, + const FuzzTestBytesSink* sink); + + // Constructs an adapter of the test into `adapter_out`. Any diagnostics + // happening during the construction or running the adapter should be emitted + // to `diagnostic_sink`. + void (*ConstructAdapter)(FuzzTestAdapterManagerCtx* ctx, + const FuzzTestDiagnosticSink* diagnostic_sink, + 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 + +#endif // FUZZTEST_CENTIPEDE_ENGINE_ABI_H_