blob: cdb1f847fc8f03a945d0c2649484d673d402192f [file]
// 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::FreeInput` 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;
// Constants for the layout of the coverage feature as a 64-bit unsigned
// integer:
//
// - Bits 63..59: 5-bit domain ID of the feature. Each domain is a
// logically independent feature namespace registered in
// `FuzzTestAdapter::SetUpCoverageDomains`.
// - Bits 58..32: 27-bit feature ID within the domain.
// - Bits 31..0: 32-bit counter value of the feature.
//
typedef enum {
kFuzzTestCoverageCounterStartBit = 0,
kFuzzTestCoverageCounterBitSize = 32,
kFuzzTestCoverageFeatureIdStartBit = 32,
kFuzzTestCoverageFeatureIdBitSize = 27,
kFuzzTestCoverageDomainIdStartBit = 59,
kFuzzTestCoverageDomainIdBitSize = 5,
} FuzzTestCoverageFeatureLayout;
// 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. See `FuzzTestCoverageFeatureLayout` for the feature
// layout.
//
// 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 FuzzTestCoverageDomainRegistryCtx
FuzzTestCoverageDomainRegistryCtx;
typedef struct {
FuzzTestCoverageDomainRegistryCtx* ctx;
// Registers a new coverage `domain`.
void (*Register)(FuzzTestCoverageDomainRegistryCtx* ctx,
const FuzzTestCoverageDomain* domain);
} FuzzTestCoverageDomainRegistry;
typedef struct FuzzTestAdapterCtx FuzzTestAdapterCtx;
typedef struct FuzzTestAdapter {
FuzzTestAdapterCtx* ctx;
// Sets up coverage domains using the domain `registry`.
// The domain registrations must be the same for the all the test adapters of
// the same test (identified by the test name and the binary).
void (*SetUpCoverageDomains)(FuzzTestAdapterCtx* ctx,
const FuzzTestCoverageDomainRegistry* registry);
// [Optional] Emits any preset seed inputs of the test using `sink`.
// The output must be the same for the all the test adapters of the same test
// (identified by the test name and the binary).
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);
// Callback to run when the engine is done with `input`.
void (*FreeInput)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle input);
// Callback to run when the engine is done with `ctx` (and the adapter).
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`. `diagnostic_sink` is guaranteed to live until
// `FreeCtx` is called on the adapter.
void (*ConstructAdapter)(FuzzTestAdapterManagerCtx* ctx,
const FuzzTestDiagnosticSink* diagnostic_sink,
FuzzTestAdapter* adapter_out);
} FuzzTestAdapterManager;
#ifdef __cplusplus
} // extern "C"
#endif
#endif // FUZZTEST_CENTIPEDE_ENGINE_ABI_H_