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/curl_global_lifecycle.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/curl_global_lifecycle.h"
8
9
#include <curl/curl.h>
10
11
#include <csignal>
12
#include <cstdio>
13
#include <cstdlib>
14
15
#include "proto_fuzzer/allocation_fault_injection.h"
16
17
namespace proto_fuzzer {
18
namespace {
19
20
CurlGlobalLifecycle* registered_lifecycles = nullptr;
21
22
}  // namespace
23
24
/// Initialize curl and its allocation hooks for this process.
25
/// @param cleanup Optional cleanup callback used by focused lifecycle tests.
26
CurlGlobalLifecycle::CurlGlobalLifecycle(CleanupFunction cleanup) noexcept
27
60
    : cleanup_(cleanup != nullptr ? cleanup : &curl_global_cleanup) {
28
  // Curl_tls_keylog_open() runs once during global initialization. Keep the
29
  // default output bounded while allowing a reproducer to select another path.
30
60
  (void)setenv("SSLKEYLOGFILE", "/dev/null", 0);
31
32
  // Mock-peer teardown can race a write. Surface that as a socket error rather
33
  // than allowing SIGPIPE to terminate the process.
34
60
  std::signal(SIGPIPE, SIG_IGN);
35
36
60
  const bool callbacks_active = allocation_fault_injection::InitializeCurl();
37
60
  if (allocation_fault_injection::ClaimCurlInitializationReference()) {
38
60
    ++initialization_count_;
39
60
  }
40
60
  if (!callbacks_active) {
41
0
    std::fputs("warning: libcurl allocation fault injection is unavailable\n", stderr);
42
0
  }
43
60
  if (initialization_count_ == 0 && curl_global_init(CURL_GLOBAL_ALL) == CURLE_OK) {
44
0
    ++initialization_count_;
45
0
  }
46
60
  initialized_ = initialization_count_ != 0;
47
60
  next_registered_ = registered_lifecycles;
48
60
  registered_lifecycles = this;
49
60
}
50
51
0
CurlGlobalLifecycle::~CurlGlobalLifecycle() {
52
0
  FinalizeForProcessExit();
53
0
  CurlGlobalLifecycle** link = &registered_lifecycles;
54
0
  while (*link != nullptr && *link != this) {
55
0
    link = &(*link)->next_registered_;
56
0
  }
57
0
  if (*link == this) {
58
0
    *link = next_registered_;
59
0
  }
60
0
  next_registered_ = nullptr;
61
0
}
62
63
/// Release this object's references after the fuzz engine has stopped.
64
2
void CurlGlobalLifecycle::FinalizeForProcessExit() noexcept {
65
2
  if (!initialized_) {
66
0
    return;
67
0
  }
68
2
  allocation_fault_injection::Reset();
69
4
  while (initialization_count_ != 0) {
70
2
    cleanup_();
71
2
    --initialization_count_;
72
2
  }
73
2
  initialized_ = false;
74
2
}
75
76
/// Finalize all registered process lifecycles before static destruction.
77
2
void FinalizeRegisteredCurlGlobalLifecyclesForExit() noexcept {
78
4
  for (CurlGlobalLifecycle* lifecycle = registered_lifecycles; lifecycle != nullptr;
79
2
       lifecycle = lifecycle->next_registered_) {
80
2
    lifecycle->FinalizeForProcessExit();
81
2
  }
82
2
}
83
84
}  // namespace proto_fuzzer