/src/curl_fuzzer/proto_fuzzer/api_coverage_probes.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al. |
3 | | * |
4 | | * SPDX-License-Identifier: curl |
5 | | */ |
6 | | |
7 | | #include "proto_fuzzer/api_coverage_probes.h" |
8 | | |
9 | | #include <curl/curl.h> |
10 | | |
11 | | #include "full_coverage/dynamic_formatting.h" |
12 | | #include "full_coverage/public_api.h" |
13 | | #include "full_coverage/utility_api.h" |
14 | | #include "proto_fuzzer/allocation_fault_injection.h" |
15 | | #include "proto_fuzzer/curl_global_lifecycle.h" |
16 | | |
17 | | namespace proto_fuzzer { |
18 | | namespace { |
19 | | |
20 | | /** Balance the API probe's public global reference only at process exit. */ |
21 | | class DeferredCurlGlobalReference final { |
22 | | public: |
23 | 2 | DeferredCurlGlobalReference() : initialized_(curl_global_init(CURL_GLOBAL_ALL) == CURLE_OK) {} |
24 | | |
25 | 2 | ~DeferredCurlGlobalReference() { |
26 | 2 | if (initialized_) { |
27 | | // Drop this probe's public reference, then ask the registered owner to |
28 | | // release its own base reference. This destructor was registered from |
29 | | // LLVMFuzzerInitialize, so final resolver/TLS cleanup runs before LLVM's |
30 | | // profile writer. The owner's later destructor is then a no-op. |
31 | 2 | curl_global_cleanup(); |
32 | 2 | FinalizeRegisteredCurlGlobalLifecyclesForExit(); |
33 | 2 | } |
34 | 2 | } |
35 | | |
36 | | DeferredCurlGlobalReference(const DeferredCurlGlobalReference&) = delete; |
37 | | DeferredCurlGlobalReference& operator=(const DeferredCurlGlobalReference&) = delete; |
38 | | |
39 | | private: |
40 | | bool initialized_; |
41 | | }; |
42 | | |
43 | | } // namespace |
44 | | |
45 | | /** |
46 | | * Run bounded curl API probes once without tearing down global state. |
47 | | * |
48 | | * The caller normally owns an initialized curl runtime. This function retains |
49 | | * one public global reference until process exit, so repeated calls are safe |
50 | | * and perform no additional work. Both LLVMFuzzerInitialize and the first |
51 | | * input callback can therefore provide reachability without per-input cost. |
52 | | */ |
53 | 11.9k | void RunApiCoverageProbesOnce() { |
54 | | // This function-local lifetime begins after the proto runtime's static |
55 | | // bootstrap, so its destructor can finalize curl before the bootstrap's |
56 | | // idempotent destructor and LLVM's profile write. |
57 | 11.9k | static const DeferredCurlGlobalReference global_reference; |
58 | 11.9k | static const bool completed = [] { |
59 | | // These are harness-owned deterministic allocations, not part of a |
60 | | // Scenario's fault plan. The initialization hook normally runs before a |
61 | | // plan can be armed; suppression also makes the callback fallback safe. |
62 | 2 | allocation_fault_injection::ScopedFailureSuppression suppress_failures; |
63 | 2 | full_coverage::ExercisePublicApiCoverageWithInitializedCurl(); |
64 | 2 | full_coverage::ExerciseUtilityApiCoverageWithInitializedCurl(); |
65 | 2 | full_coverage::ExerciseDynamicFormattingCoverage(); |
66 | 2 | return true; |
67 | 2 | }(); |
68 | 11.9k | (void)global_reference; |
69 | 11.9k | (void)completed; |
70 | 11.9k | } |
71 | | |
72 | | } // namespace proto_fuzzer |