10#ifndef PROTO_FUZZER_PROFILE_FUZZER_H_
11#define PROTO_FUZZER_PROFILE_FUZZER_H_
13#include <libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h>
19#include "curl_fuzzer.pb.h"
23namespace proto_fuzzer {
32 using CustomMutator = std::size_t (*)(std::uint8_t*, std::size_t, std::size_t,
unsigned int);
34 using CustomCrossOver = std::size_t (*)(
const std::uint8_t*, std::size_t,
const std::uint8_t*, std::size_t,
35 std::uint8_t*, std::size_t,
unsigned int);
37 using InputLoader = bool (*)(
const std::uint8_t*, std::size_t, curl::fuzzer::proto::Scenario*);
68template <
typename Traits>
78 static const protobuf_mutator::libfuzzer::PostProcessorRegistration<Message> registration(
87 if (message ==
nullptr) {
91 message->DiscardUnknownFields();
93 Traits::Lower(message, &runtime);
98 Traits::Lift(&runtime, message);
107 static std::size_t
CustomMutator(std::uint8_t* data, std::size_t size, std::size_t max_size,
unsigned int seed) {
110 return protobuf_mutator::libfuzzer::CustomProtoMutator(
true, data, size, max_size, seed, &message);
122 static std::size_t
CustomCrossOver(
const std::uint8_t* data1, std::size_t size1,
const std::uint8_t* data2,
123 std::size_t size2, std::uint8_t* out, std::size_t max_out_size,
128 return protobuf_mutator::libfuzzer::CustomProtoCrossOver(
true, data1, size1, data2, size2, out, max_out_size, seed,
129 &message1, &message2);
142 if (runtime ==
nullptr) {
148 if (!protobuf_mutator::libfuzzer::LoadProtoInput(
true, data, size, &message)) {
155 message.DiscardUnknownFields();
157 Traits::Lower(&message, runtime);
175template <
typename Traits>
176bool LoadProfileInput(
const std::uint8_t* data, std::size_t size, curl::fuzzer::proto::Scenario* runtime) {
182template <
typename Traits>
184 static const bool mutation_helpers_probed = [] {
185 constexpr std::size_t kBufferSize = 1024;
186 constexpr unsigned int kMutationSeed = 0x4355524cU;
188 curl::fuzzer::proto::Scenario runtime;
191 typename Traits::Message message;
192 Traits::Lift(&runtime, &message);
193 std::array<std::uint8_t, kBufferSize> first = {};
194 const std::size_t original_size = message.ByteSizeLong();
195 if (original_size > first.size()) {
198 (void)message.SerializeWithCachedSizesToArray(first.data());
201 std::array<std::uint8_t, kBufferSize> second = first;
202 std::array<std::uint8_t, kBufferSize> child = {};
203 const std::size_t mutated_size = Hooks::CustomMutator(first.data(), original_size, first.size(), kMutationSeed);
204 const std::size_t crossed_size = Hooks::CustomCrossOver(first.data(), mutated_size, second.data(), original_size,
205 child.data(), child.size(), kMutationSeed);
206 const volatile std::size_t result_sizes[] = {mutated_size, crossed_size};
210 (void)mutation_helpers_probed;
216template <
typename Traits>
Bind all LPM operations for one process to one protobuf message type.
static std::size_t CustomCrossOver(const std::uint8_t *data1, std::size_t size1, const std::uint8_t *data2, std::size_t size2, std::uint8_t *out, std::size_t max_out_size, unsigned int seed)
Cross two binary profile messages using the same type as mutation/load.
static void NormalizeMessage(Message *message)
Remove unknown wire data, normalize through the common runtime model, and lift back into the same gen...
static void EnsurePostProcessor()
Register the profile postprocessor before the first LPM operation.
static std::size_t CustomMutator(std::uint8_t *data, std::size_t size, std::size_t max_size, unsigned int seed)
Mutate a binary profile message and retain its exact type in LPM's cache.
curl::fuzzer::proto::Scenario RuntimeScenario
Shared internal Scenario consumed by the runtime.
static bool LoadAndLower(const std::uint8_t *data, std::size_t size, RuntimeScenario *runtime)
Load one binary profile message and transfer it into owned runtime state.
typename Traits::Message Message
Concrete generated protobuf root for this target profile.
void ProbeTimingMutationHelpers()
Exercise the typed mutation ABI once for the profiling timing target.
bool LoadProfileInput(const std::uint8_t *data, std::size_t size, curl::fuzzer::proto::Scenario *runtime)
Load one generated profile message and lower it into runtime state.
constexpr ProfileFuzzerTraits BindProfileFuzzer()
Bind one generated adapter to the ordinary entrypoint helper interface.
Ordinary runtime binding for one generated protobuf profile.
bool(*)(const std::uint8_t *, std::size_t, curl::fuzzer::proto::Scenario *) InputLoader
Parse and lower one input using the bound message type.
CustomCrossOver custom_crossover
Typed crossover callback.
CustomMutator custom_mutator
Typed mutation callback.
std::size_t(*)(const std::uint8_t *, std::size_t, const std::uint8_t *, std::size_t, std::uint8_t *, std::size_t, unsigned int) CustomCrossOver
libFuzzer custom-crossover callback for the bound message type.
void(*)() MutationProbe
Optional profiling-only callback that exercises typed mutation helpers.
TargetProfile profile
Runtime policy permanently associated with all callbacks.
MutationProbe probe_mutation_helpers
Timing-profile probe, or nullptr for ordinary profiles.
std::size_t(*)(std::uint8_t *, std::size_t, std::size_t, unsigned int) CustomMutator
libFuzzer custom-mutator callback for the bound message type.
InputLoader load_input
Typed parse-and-lower callback.
void NormalizeScenarioForTarget(curl::fuzzer::proto::Scenario *scenario, TargetProfile profile, ConditionalEligibilityPruner prune_conditional_eligibility)
Complete normalization for a loaded or mutated fixed-target Scenario.
Mutation policies that keep each proto fuzzer in one intentional performance and protocol lane.
Compile-time identities and execution modes for proto fuzz targets.
TargetProfile
Identifies one compiled proto-fuzzer lane.
@ kTiming
Isolate deterministic backpressure and timed-wait behavior.
@ kCompatibility
Preserve the original mixed target and its accumulated corpus exactly.