Refine the ABI spec on Free* and the lifetime of diagnostic sink. PiperOrigin-RevId: 1008908895
diff --git a/centipede/engine_abi.h b/centipede/engine_abi.h index cdb1f84..d43c19f 100644 --- a/centipede/engine_abi.h +++ b/centipede/engine_abi.h
@@ -205,9 +205,16 @@ FuzzTestInputHandle input); // Callback to run when the engine is done with `input`. + // + // The engine calls this at most once on each input emitted to the engine, + // even if any error has been emitted. void (*FreeInput)(FuzzTestAdapterCtx* ctx, FuzzTestInputHandle input); // Callback to run when the engine is done with `ctx` (and the adapter). + // + // The engine calls this at most once on each adapter after + // `ConstructAdapter`, even if any error has been emitted (including during + // `ConstructAdapter`). void (*FreeCtx)(FuzzTestAdapterCtx* ctx); } FuzzTestAdapter; @@ -225,8 +232,11 @@ // 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. + // to `diagnostic_sink`. + // + // When this returns, `adapter_out->FreeCtx` must be set, even if any error + // has been emitted to `diagnostic_sink`. `diagnostic_sink` is guaranteed to + // stay alive until the `FreeCtx` call on the adapter has returned. void (*ConstructAdapter)(FuzzTestAdapterManagerCtx* ctx, const FuzzTestDiagnosticSink* diagnostic_sink, FuzzTestAdapter* adapter_out);
diff --git a/rust/engine/src/engine_ffi.rs b/rust/engine/src/engine_ffi.rs index 276b3e1..6eb2542 100644 --- a/rust/engine/src/engine_ffi.rs +++ b/rust/engine/src/engine_ffi.rs
@@ -192,12 +192,10 @@ /// 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 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. -/// pub struct FuzzTestCoverageFeatureLayout; impl FuzzTestCoverageFeatureLayout { @@ -377,10 +375,17 @@ >, /// Callback to run when the engine is done with `input`. + /// + /// The engine calls this at most once on each input emitted to the engine, + /// even if any error has been emitted. pub free_input: Option<unsafe extern "C" fn(ctx: *mut FuzzTestAdapterCtx, input: FuzzTestInputHandle)>, /// Callback to run when the engine is done with `ctx` (and the adapter). + /// + /// The engine calls this at most once on each adapter after + /// `ConstructAdapter`, even if any error has been emitted (including during + /// `ConstructAdapter`). pub free_ctx: Option<unsafe extern "C" fn(ctx: *mut FuzzTestAdapterCtx)>, } @@ -407,8 +412,11 @@ /// 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. + /// to `diagnostic_sink`. + /// + /// When this returns, `adapter_out->FreeCtx` must be set, even if any error + /// has been emitted to `diagnostic_sink`. `diagnostic_sink` is guaranteed to + /// stay alive until the `FreeCtx` call on the adapter has returned. pub construct_adapter: Option< unsafe extern "C" fn( ctx: *mut FuzzTestAdapterManagerCtx,
diff --git a/rust/engine/src/lib.rs b/rust/engine/src/lib.rs index f6e0bf8..7ee36e6 100644 --- a/rust/engine/src/lib.rs +++ b/rust/engine/src/lib.rs
@@ -66,7 +66,7 @@ /// * `raw` is a non-null, properly aligned pointer to a valid `FuzzTestDiagnosticSink`. /// * `(*raw).ctx` is a valid context pointer. /// * The sink and its context remain valid for the duration of `DiagnosticSink`'s usage - /// (guaranteed by the engine until `FreeCtx` is called on the adapter). + /// (guaranteed by the engine until the `FreeCtx` call on the adapter has returned). pub unsafe fn from_raw(raw: *const engine_ffi::FuzzTestDiagnosticSink) -> Self { // SAFETY: Caller guarantees `raw` is a valid pointer to `FuzzTestDiagnosticSink`. let raw_sink = unsafe { *raw }; @@ -124,8 +124,8 @@ /// The caller must ensure that: /// * `raw` is a non-null, properly aligned pointer to a valid `FuzzTestBytesSink`. /// * `(*raw).ctx` is a valid context pointer. - /// * The sink and its context remain valid for the duration of `BytesSink`'s usage - /// (guaranteed by the engine until `FreeCtx` is called on the adapter). + /// * The sink and its context remain valid for the duration of `BytesSink`'s usage (guaranteed + /// by the engine until `FreeCtx` is called on the adapter). pub unsafe fn from_raw(raw: *const engine_ffi::FuzzTestBytesSink) -> Self { // SAFETY: Caller guarantees `raw` is a valid pointer to `FuzzTestBytesSink`. let raw_sink = unsafe { *raw }; @@ -158,8 +158,8 @@ /// The caller must ensure that: /// * `raw` is a non-null, properly aligned pointer to a valid `FuzzTestInputSink`. /// * `(*raw).ctx` is a valid context pointer. - /// * The sink and its context remain valid for the duration of `InputSink`'s usage - /// (guaranteed by the engine until `FreeCtx` is called on the adapter). + /// * The sink and its context remain valid for the duration of `InputSink`'s usage (guaranteed + /// by the engine until `FreeCtx` is called on the adapter). pub unsafe fn from_raw(raw: *const engine_ffi::FuzzTestInputSink) -> Self { // SAFETY: Caller guarantees `raw` is a valid pointer to `FuzzTestInputSink`. let raw_sink = unsafe { *raw }; @@ -269,8 +269,8 @@ /// The caller must ensure that: /// * `raw` is a non-null, properly aligned pointer to a valid `FuzzTestCoverageDomainRegistry`. /// * `(*raw).ctx` is a valid context pointer. - /// * The registry and its context remain valid for the duration of `CoverageDomainRegistry`'s usage - /// (guaranteed by the engine until `FreeCtx` is called on the adapter). + /// * The registry and its context remain valid for the duration of `CoverageDomainRegistry`'s + /// usage (guaranteed by the engine until `FreeCtx` is called on the adapter). pub unsafe fn from_raw(raw: *const engine_ffi::FuzzTestCoverageDomainRegistry) -> Self { // SAFETY: Caller guarantees `raw` is a valid pointer to `FuzzTestCoverageDomainRegistry`. let raw_registry = unsafe { *raw };
diff --git a/rust/src/worker.rs b/rust/src/worker.rs index fcfbd6a..0ca12e9 100644 --- a/rust/src/worker.rs +++ b/rust/src/worker.rs
@@ -343,7 +343,7 @@ /// The caller must ensure that: /// * `ctx` is a valid pointer to the `RustFuzzTestAdapterManager` passed during initialization. /// * `diagnostic_sink` is a valid pointer to a `FuzzTestDiagnosticSink` whose lifetime extends -/// until `FreeCtx` is called on the adapter. +/// until the `FreeCtx` call on the adapter has returned. /// * `adapter_out` is a valid pointer to write the output `FuzzTestAdapter`. pub unsafe extern "C" fn construct_adapter_callback( ctx: *mut engine_ffi::FuzzTestAdapterManagerCtx, @@ -355,7 +355,8 @@ let manager = unsafe { &*(ctx as *const RustFuzzTestAdapterManager) }; // SAFETY: The engine guarantees `diagnostic_sink` is a valid pointer to a - // `FuzzTestDiagnosticSink` whose lifetime extends until `FreeCtx` is called on the adapter. + // `FuzzTestDiagnosticSink` whose lifetime extends until the `FreeCtx` call on the adapter has + // returned. let safe_sink = unsafe { DiagnosticSink::from_raw(diagnostic_sink) }; set_diagnostic_sink(safe_sink);