Coverage Report

Created: 2026-10-28 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl_fuzzer/proto_fuzzer/fuzzer_main.cc
Line
Count
Source
1
/*
2
 * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al.
3
 *
4
 * SPDX-License-Identifier: curl
5
 */
6
7
/// @file
8
/// @brief Shared execution for profile-split protobuf targets.
9
10
#include "proto_fuzzer/fuzzer_main.h"
11
12
#include <curl/curl.h>
13
14
#include <cstdio>
15
16
#include "proto_fuzzer/allocation_fault_injection.h"
17
#include "proto_fuzzer/curl_global_lifecycle.h"
18
#include "proto_fuzzer/scenario_runner.h"
19
#include "proto_fuzzer/target_policy.h"
20
21
namespace {
22
23
// libFuzzer reuses one process, so the static object initializes curl once and
24
// releases its global resolver/TLS state only after the engine has stopped.
25
proto_fuzzer::CurlGlobalLifecycle kGlobalBootstrap;
26
27
}  // namespace
28
29
namespace proto_fuzzer {
30
31
/// Mutate one serialized generated profile message.
32
/// @param data Serialized profile message buffer to mutate in place.
33
/// @param size Number of input bytes currently stored in `data`.
34
/// @param max_size Capacity of `data` available for the mutated message.
35
/// @param seed Deterministic mutation seed supplied by libFuzzer.
36
/// @param traits Generated profile binding for this executable.
37
/// @return Number of serialized bytes in the mutated message.
38
std::size_t ProtoFuzzerCustomMutator(std::uint8_t* data, std::size_t size, std::size_t max_size, unsigned int seed,
39
0
                                     const ProfileFuzzerTraits& traits) {
40
0
  allocation_fault_injection::Reset();
41
0
  if (traits.custom_mutator == nullptr) {
42
0
    return 0;
43
0
  }
44
0
  return traits.custom_mutator(data, size, max_size, seed);
45
0
}
46
47
/// Cross two serialized generated profile messages of the same concrete type.
48
/// @param data1 Serialized first parent message.
49
/// @param size1 Number of bytes in `data1`.
50
/// @param data2 Serialized second parent message.
51
/// @param size2 Number of bytes in `data2`.
52
/// @param out Destination buffer for the crossed message.
53
/// @param max_out_size Capacity of `out`.
54
/// @param seed Deterministic crossover seed supplied by libFuzzer.
55
/// @param traits Generated profile binding for this executable.
56
/// @return Number of serialized bytes written to `out`.
57
std::size_t ProtoFuzzerCustomCrossOver(const std::uint8_t* data1, std::size_t size1, const std::uint8_t* data2,
58
                                       std::size_t size2, std::uint8_t* out, std::size_t max_out_size,
59
0
                                       unsigned int seed, const ProfileFuzzerTraits& traits) {
60
0
  allocation_fault_injection::Reset();
61
0
  if (traits.custom_crossover == nullptr) {
62
0
    return 0;
63
0
  }
64
0
  return traits.custom_crossover(data1, size1, data2, size2, out, max_out_size, seed);
65
0
}
66
67
/// Load and execute one generated-profile input under its fixed target lane.
68
/// @param data Serialized generated-profile input bytes.
69
/// @param size Number of bytes available at `data`.
70
/// @param traits Generated profile binding selected by the entrypoint.
71
/// @return Always zero, as required by the libFuzzer entrypoint contract.
72
245k
int ProtoFuzzerTestOneInput(const std::uint8_t* data, std::size_t size, const ProfileFuzzerTraits& traits) {
73
245k
  allocation_fault_injection::Reset();
74
245k
#if defined(PROTO_FUZZER_OBSERVE_STATE)
75
245k
  if (traits.probe_mutation_helpers != nullptr) {
76
10.2k
    traits.probe_mutation_helpers();
77
10.2k
  }
78
245k
#endif
79
245k
  curl::fuzzer::proto::Scenario scenario;
80
245k
  if (traits.load_input == nullptr || !traits.load_input(data, size, &scenario)) {
81
4.39k
    return 0;
82
4.39k
  }
83
84
240k
  NormalizeScenarioForExecution(&scenario);
85
240k
  allocation_fault_injection::Configure(scenario.fail_allocations().data(),
86
240k
                                        static_cast<std::size_t>(scenario.fail_allocations_size()));
87
240k
  allocation_fault_injection::Arm();
88
240k
  proto_fuzzer::RunScenario(scenario, RunModeFor(traits.profile));
89
240k
  allocation_fault_injection::Reset();
90
240k
  if (traits.profile == TargetProfile::kResolver &&
91
7.85k
      scenario.resolver_mode() == curl::fuzzer::proto::RESOLVER_MODE_GLOBAL_LIFECYCLE) {
92
143
    curl_global_cleanup();
93
143
    if (!allocation_fault_injection::ReinitializeCurl()) {
94
0
      std::fputs("warning: libcurl reinitialization failed\n", stderr);
95
0
      (void)curl_global_init(CURL_GLOBAL_ALL);
96
0
    }
97
143
  }
98
240k
  return 0;
99
245k
}
100
101
}  // namespace proto_fuzzer