Coverage Report

Created: 2026-10-15 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl_fuzzer/openssl_contract_shim.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 <openssl/ssl.h>
8
9
#include <array>
10
#include <atomic>
11
#include <cstddef>
12
#include <cstdio>
13
#include <cstdlib>
14
#include <mutex>
15
#include <type_traits>
16
17
namespace {
18
19
// SSL_get_error classifies a preceding I/O result for one SSL object. Keep
20
// pending results keyed by that object so interleaved connections cannot
21
// replace one another's classification state.
22
struct PendingIoCall {
23
  const SSL *ssl = nullptr;
24
  const char *api = nullptr;
25
  long long result = 0;
26
};
27
28
struct FatalConnection {
29
  const SSL *ssl = nullptr;
30
  const char *io_api = nullptr;
31
  long long io_result = 0;
32
  int ssl_error = SSL_ERROR_NONE;
33
};
34
35
// Fixed tables keep allocation-failure fuzzing from disabling or perturbing
36
// the monitor.
37
constexpr std::size_t kMaximumTrackedConnections = 256;
38
std::array<PendingIoCall, kMaximumTrackedConnections> pending_io_calls{};
39
std::mutex pending_io_calls_mutex;
40
std::atomic<std::size_t> pending_io_call_count{0};
41
42
constexpr std::size_t kMaximumFatalConnections = kMaximumTrackedConnections;
43
std::array<FatalConnection, kMaximumFatalConnections> fatal_connections{};
44
std::mutex fatal_connections_mutex;
45
std::atomic<std::size_t> fatal_connection_count{0};
46
47
// Static libssl contains calls to public SSL APIs. --wrap redirects those
48
// calls too, so calls made while a real OpenSSL function is running bypass the
49
// monitor and cannot replace the application call being classified.
50
thread_local unsigned real_call_depth = 0;
51
52
class RealCallScope {
53
public:
54
6.98M
  RealCallScope() { ++real_call_depth; }
55
6.98M
  ~RealCallScope() { --real_call_depth; }
56
57
  RealCallScope(const RealCallScope &) = delete;
58
  RealCallScope &operator=(const RealCallScope &) = delete;
59
};
60
61
7.22M
bool IsRealCallActive() { return real_call_depth != 0; }
62
63
0
const char *ErrorName(int ssl_error) {
64
0
  switch (ssl_error) {
65
0
  case SSL_ERROR_SSL:
66
0
    return "SSL_ERROR_SSL";
67
0
  case SSL_ERROR_SYSCALL:
68
0
    return "SSL_ERROR_SYSCALL";
69
0
  default:
70
0
    return "unknown fatal error";
71
0
  }
72
0
}
73
74
[[noreturn]] void AbortContractViolation(const char *attempted_api,
75
0
                                         const FatalConnection &fatal) {
76
0
  std::fprintf(stderr,
77
0
               "OpenSSL contract assertion failed: %s called on SSL %p "
78
0
               "after %s returned %lld and SSL_get_error classified it as "
79
0
               "%s; no further I/O or SSL_shutdown is allowed\n",
80
0
               attempted_api, static_cast<const void *>(fatal.ssl),
81
0
               fatal.io_api, fatal.io_result, ErrorName(fatal.ssl_error));
82
0
  std::fflush(stderr);
83
0
  std::abort();
84
0
}
85
86
0
[[noreturn]] void AbortPendingOverflow(const PendingIoCall &call) {
87
0
  std::fprintf(stderr,
88
0
               "OpenSSL contract assertion failed: cannot track SSL %p "
89
0
               "after %s returned %lld; pending-I/O table is full\n",
90
0
               static_cast<const void *>(call.ssl), call.api, call.result);
91
0
  std::fflush(stderr);
92
0
  std::abort();
93
0
}
94
95
0
[[noreturn]] void AbortFatalOverflow(const PendingIoCall &call, int ssl_error) {
96
0
  std::fprintf(stderr,
97
0
               "OpenSSL contract assertion failed: cannot track SSL %p "
98
0
               "after %s returned %lld and SSL_get_error classified it as "
99
0
               "%s; fatal-connection table is full\n",
100
0
               static_cast<const void *>(call.ssl), call.api, call.result,
101
0
               ErrorName(ssl_error));
102
0
  std::fflush(stderr);
103
0
  std::abort();
104
0
}
105
106
4.81M
PendingIoCall *FindPendingIoCall(const SSL *ssl) {
107
618M
  for (PendingIoCall &call : pending_io_calls) {
108
618M
    if (call.ssl == ssl) {
109
2.40M
      return &call;
110
2.40M
    }
111
618M
  }
112
2.40M
  return nullptr;
113
4.81M
}
114
115
31.4k
FatalConnection *FindFatalConnection(const SSL *ssl) {
116
5.05M
  for (FatalConnection &fatal : fatal_connections) {
117
5.05M
    if (fatal.ssl == ssl) {
118
11.7k
      return &fatal;
119
11.7k
    }
120
5.05M
  }
121
19.7k
  return nullptr;
122
31.4k
}
123
124
4.08M
void CheckUsable(const SSL *ssl, const char *attempted_api) {
125
4.08M
  if (ssl == nullptr ||
126
4.08M
      fatal_connection_count.load(std::memory_order_acquire) == 0) {
127
4.07M
    return;
128
4.07M
  }
129
130
7.18k
  FatalConnection fatal;
131
7.18k
  {
132
7.18k
    std::lock_guard<std::mutex> lock(fatal_connections_mutex);
133
7.18k
    const FatalConnection *tracked = FindFatalConnection(ssl);
134
7.18k
    if (tracked != nullptr) {
135
0
      fatal = *tracked;
136
0
    }
137
7.18k
  }
138
7.18k
  if (fatal.ssl != nullptr) {
139
0
    AbortContractViolation(attempted_api, fatal);
140
0
  }
141
7.18k
}
142
143
2.17M
void ForgetPendingIoCall(const SSL *ssl) {
144
2.17M
  if (ssl == nullptr ||
145
2.17M
      pending_io_call_count.load(std::memory_order_acquire) == 0) {
146
2.15M
    return;
147
2.15M
  }
148
149
16.4k
  std::lock_guard<std::mutex> lock(pending_io_calls_mutex);
150
16.4k
  PendingIoCall *call = FindPendingIoCall(ssl);
151
16.4k
  if (call != nullptr) {
152
16.4k
    *call = PendingIoCall{};
153
16.4k
    pending_io_call_count.fetch_sub(1, std::memory_order_release);
154
16.4k
  }
155
16.4k
}
156
157
void RecordIoResult(const SSL *ssl, const char *api, long long result,
158
4.08M
                    bool zero_is_non_error = false) {
159
4.08M
  if (ssl == nullptr) {
160
0
    return;
161
0
  }
162
4.08M
  if (result > 0 || (zero_is_non_error && result == 0)) {
163
1.68M
    ForgetPendingIoCall(ssl);
164
1.68M
    return;
165
1.68M
  }
166
167
2.40M
  PendingIoCall recorded;
168
2.40M
  recorded.ssl = ssl;
169
2.40M
  recorded.api = api;
170
2.40M
  recorded.result = result;
171
2.40M
  bool table_full = false;
172
2.40M
  bool added = false;
173
2.40M
  {
174
2.40M
    std::lock_guard<std::mutex> lock(pending_io_calls_mutex);
175
2.40M
    PendingIoCall *call = FindPendingIoCall(ssl);
176
2.40M
    if (call == nullptr) {
177
2.40M
      for (PendingIoCall &entry : pending_io_calls) {
178
2.40M
        if (entry.ssl == nullptr) {
179
2.40M
          call = &entry;
180
2.40M
          added = true;
181
2.40M
          break;
182
2.40M
        }
183
2.40M
      }
184
2.40M
    }
185
2.40M
    if (call != nullptr) {
186
2.40M
      *call = recorded;
187
2.40M
      if (added) {
188
2.40M
        pending_io_call_count.fetch_add(1, std::memory_order_release);
189
2.40M
      }
190
2.40M
    } else {
191
0
      table_full = true;
192
0
    }
193
2.40M
  }
194
2.40M
  if (table_full) {
195
0
    AbortPendingOverflow(recorded);
196
0
  }
197
2.40M
}
198
199
2.40M
void RecordSslError(const SSL *ssl, int io_result, int ssl_error) {
200
2.40M
  if (ssl == nullptr ||
201
2.40M
      pending_io_call_count.load(std::memory_order_acquire) == 0) {
202
15.3k
    return;
203
15.3k
  }
204
205
2.38M
  PendingIoCall classified_call;
206
2.38M
  {
207
2.38M
    std::lock_guard<std::mutex> lock(pending_io_calls_mutex);
208
2.38M
    PendingIoCall *pending = FindPendingIoCall(ssl);
209
2.38M
    if (pending == nullptr || pending->result != io_result) {
210
0
      return;
211
0
    }
212
2.38M
    classified_call = *pending;
213
2.38M
    *pending = PendingIoCall{};
214
2.38M
    pending_io_call_count.fetch_sub(1, std::memory_order_release);
215
2.38M
  }
216
2.38M
  if (ssl_error != SSL_ERROR_SSL && ssl_error != SSL_ERROR_SYSCALL) {
217
2.37M
    return;
218
2.37M
  }
219
220
11.7k
  bool table_full = false;
221
11.7k
  bool added = false;
222
11.7k
  {
223
11.7k
    std::lock_guard<std::mutex> lock(fatal_connections_mutex);
224
11.7k
    FatalConnection *fatal = FindFatalConnection(ssl);
225
11.7k
    if (fatal == nullptr) {
226
12.1k
      for (FatalConnection &entry : fatal_connections) {
227
12.1k
        if (entry.ssl == nullptr) {
228
11.7k
          fatal = &entry;
229
11.7k
          added = true;
230
11.7k
          break;
231
11.7k
        }
232
12.1k
      }
233
11.7k
    }
234
11.7k
    if (fatal != nullptr) {
235
11.7k
      fatal->ssl = ssl;
236
11.7k
      fatal->io_api = classified_call.api;
237
11.7k
      fatal->io_result = classified_call.result;
238
11.7k
      fatal->ssl_error = ssl_error;
239
11.7k
      if (added) {
240
11.7k
        fatal_connection_count.fetch_add(1, std::memory_order_release);
241
11.7k
      }
242
11.7k
    } else {
243
0
      table_full = true;
244
0
    }
245
11.7k
  }
246
11.7k
  if (table_full) {
247
0
    AbortFatalOverflow(classified_call, ssl_error);
248
0
  }
249
11.7k
}
250
251
491k
void ForgetConnection(const SSL *ssl) {
252
491k
  ForgetPendingIoCall(ssl);
253
491k
  if (ssl == nullptr ||
254
491k
      fatal_connection_count.load(std::memory_order_acquire) == 0) {
255
479k
    return;
256
479k
  }
257
258
12.5k
  std::lock_guard<std::mutex> lock(fatal_connections_mutex);
259
12.5k
  FatalConnection *fatal = FindFatalConnection(ssl);
260
12.5k
  if (fatal != nullptr) {
261
11.7k
    *fatal = FatalConnection{};
262
11.7k
    fatal_connection_count.fetch_sub(1, std::memory_order_release);
263
11.7k
  }
264
12.5k
}
265
266
} // namespace
267
268
// GNU ld and lld provide each __real_* symbol when the final link uses the
269
// matching --wrap option. decltype ties these declarations to the installed
270
// OpenSSL headers and makes signature drift a compile-time failure.
271
extern "C" decltype(SSL_new) __real_SSL_new;
272
extern "C" decltype(SSL_free) __real_SSL_free;
273
extern "C" decltype(SSL_clear) __real_SSL_clear;
274
extern "C" decltype(SSL_get_error) __real_SSL_get_error;
275
extern "C" decltype(SSL_accept) __real_SSL_accept;
276
extern "C" decltype(SSL_connect) __real_SSL_connect;
277
extern "C" decltype(SSL_do_handshake) __real_SSL_do_handshake;
278
extern "C" decltype(SSL_read) __real_SSL_read;
279
extern "C" decltype(SSL_read_ex) __real_SSL_read_ex;
280
extern "C" decltype(SSL_read_early_data) __real_SSL_read_early_data;
281
extern "C" decltype(SSL_peek) __real_SSL_peek;
282
extern "C" decltype(SSL_peek_ex) __real_SSL_peek_ex;
283
extern "C" decltype(SSL_sendfile) __real_SSL_sendfile;
284
extern "C" decltype(SSL_write) __real_SSL_write;
285
extern "C" decltype(SSL_write_ex) __real_SSL_write_ex;
286
extern "C" decltype(SSL_write_ex2) __real_SSL_write_ex2;
287
extern "C" decltype(SSL_write_early_data) __real_SSL_write_early_data;
288
extern "C" decltype(SSL_shutdown) __real_SSL_shutdown;
289
extern "C" decltype(SSL_shutdown_ex) __real_SSL_shutdown_ex;
290
291
245k
extern "C" SSL *__wrap_SSL_new(SSL_CTX *ctx) {
292
245k
  if (IsRealCallActive()) {
293
0
    return __real_SSL_new(ctx);
294
0
  }
295
245k
  SSL *ssl;
296
245k
  {
297
245k
    RealCallScope real_call;
298
245k
    ssl = __real_SSL_new(ctx);
299
245k
  }
300
  // OpenSSL's allocator may reuse a recently freed address.
301
245k
  ForgetConnection(ssl);
302
245k
  return ssl;
303
245k
}
304
static_assert(std::is_same<decltype(SSL_new), decltype(__wrap_SSL_new)>::value,
305
              "SSL_new signature changed");
306
307
245k
extern "C" void __wrap_SSL_free(SSL *ssl) {
308
245k
  if (IsRealCallActive()) {
309
0
    __real_SSL_free(ssl);
310
0
    return;
311
0
  }
312
245k
  ForgetConnection(ssl);
313
245k
  RealCallScope real_call;
314
245k
  __real_SSL_free(ssl);
315
245k
}
316
static_assert(
317
    std::is_same<decltype(SSL_free), decltype(__wrap_SSL_free)>::value,
318
    "SSL_free signature changed");
319
320
244k
extern "C" int __wrap_SSL_clear(SSL *ssl) {
321
244k
  if (IsRealCallActive()) {
322
244k
    return __real_SSL_clear(ssl);
323
244k
  }
324
0
  int result;
325
0
  {
326
0
    RealCallScope real_call;
327
0
    result = __real_SSL_clear(ssl);
328
0
  }
329
0
  if (result == 1) {
330
    // A successful clear starts a new connection on the same SSL object.
331
0
    ForgetConnection(ssl);
332
0
  }
333
0
  return result;
334
244k
}
335
static_assert(
336
    std::is_same<decltype(SSL_clear), decltype(__wrap_SSL_clear)>::value,
337
    "SSL_clear signature changed");
338
339
2.40M
extern "C" int __wrap_SSL_get_error(const SSL *ssl, int io_result) {
340
2.40M
  if (IsRealCallActive()) {
341
446
    return __real_SSL_get_error(ssl, io_result);
342
446
  }
343
2.40M
  int ssl_error;
344
2.40M
  {
345
2.40M
    RealCallScope real_call;
346
2.40M
    ssl_error = __real_SSL_get_error(ssl, io_result);
347
2.40M
  }
348
2.40M
  RecordSslError(ssl, io_result, ssl_error);
349
2.40M
  return ssl_error;
350
2.40M
}
351
static_assert(std::is_same<decltype(SSL_get_error),
352
                           decltype(__wrap_SSL_get_error)>::value,
353
              "SSL_get_error signature changed");
354
355
#define DEFINE_IO_WRAPPER_WITH_POLICY(name, parameters, arguments,             \
356
                                      zero_is_non_error)                       \
357
  extern "C" auto __wrap_##name parameters                                     \
358
4.08M
      ->decltype(__real_##name arguments) {                                    \
359
4.08M
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
4.08M
    CheckUsable(ssl, #name);                                                   \
363
4.08M
    decltype(__real_##name arguments) result;                                  \
364
4.08M
    {                                                                          \
365
4.08M
      RealCallScope real_call;                                                 \
366
4.08M
      result = __real_##name arguments;                                        \
367
4.08M
    }                                                                          \
368
4.08M
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
4.08M
                   zero_is_non_error);                                         \
370
4.08M
    return result;                                                             \
371
4.08M
  }                                                                            \
__wrap_SSL_accept
Line
Count
Source
358
379k
      ->decltype(__real_##name arguments) {                                    \
359
379k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
379k
    CheckUsable(ssl, #name);                                                   \
363
379k
    decltype(__real_##name arguments) result;                                  \
364
379k
    {                                                                          \
365
379k
      RealCallScope real_call;                                                 \
366
379k
      result = __real_##name arguments;                                        \
367
379k
    }                                                                          \
368
379k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
379k
                   zero_is_non_error);                                         \
370
379k
    return result;                                                             \
371
379k
  }                                                                            \
__wrap_SSL_connect
Line
Count
Source
358
194k
      ->decltype(__real_##name arguments) {                                    \
359
194k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
194k
    CheckUsable(ssl, #name);                                                   \
363
194k
    decltype(__real_##name arguments) result;                                  \
364
194k
    {                                                                          \
365
194k
      RealCallScope real_call;                                                 \
366
194k
      result = __real_##name arguments;                                        \
367
194k
    }                                                                          \
368
194k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
194k
                   zero_is_non_error);                                         \
370
194k
    return result;                                                             \
371
194k
  }                                                                            \
__wrap_SSL_do_handshake
Line
Count
Source
358
67.1k
      ->decltype(__real_##name arguments) {                                    \
359
67.1k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
67.1k
    CheckUsable(ssl, #name);                                                   \
363
67.1k
    decltype(__real_##name arguments) result;                                  \
364
67.1k
    {                                                                          \
365
67.1k
      RealCallScope real_call;                                                 \
366
67.1k
      result = __real_##name arguments;                                        \
367
67.1k
    }                                                                          \
368
67.1k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
67.1k
                   zero_is_non_error);                                         \
370
67.1k
    return result;                                                             \
371
67.1k
  }                                                                            \
__wrap_SSL_read
Line
Count
Source
358
803k
      ->decltype(__real_##name arguments) {                                    \
359
803k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
803k
    CheckUsable(ssl, #name);                                                   \
363
803k
    decltype(__real_##name arguments) result;                                  \
364
803k
    {                                                                          \
365
803k
      RealCallScope real_call;                                                 \
366
803k
      result = __real_##name arguments;                                        \
367
803k
    }                                                                          \
368
803k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
803k
                   zero_is_non_error);                                         \
370
803k
    return result;                                                             \
371
803k
  }                                                                            \
__wrap_SSL_read_ex
Line
Count
Source
358
1.90M
      ->decltype(__real_##name arguments) {                                    \
359
1.90M
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
1.90M
    CheckUsable(ssl, #name);                                                   \
363
1.90M
    decltype(__real_##name arguments) result;                                  \
364
1.90M
    {                                                                          \
365
1.90M
      RealCallScope real_call;                                                 \
366
1.90M
      result = __real_##name arguments;                                        \
367
1.90M
    }                                                                          \
368
1.90M
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
1.90M
                   zero_is_non_error);                                         \
370
1.90M
    return result;                                                             \
371
1.90M
  }                                                                            \
Unexecuted instantiation: __wrap_SSL_read_early_data
Unexecuted instantiation: __wrap_SSL_peek
Unexecuted instantiation: __wrap_SSL_peek_ex
Unexecuted instantiation: __wrap_SSL_sendfile
__wrap_SSL_write
Line
Count
Source
358
327k
      ->decltype(__real_##name arguments) {                                    \
359
327k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
327k
    CheckUsable(ssl, #name);                                                   \
363
327k
    decltype(__real_##name arguments) result;                                  \
364
327k
    {                                                                          \
365
327k
      RealCallScope real_call;                                                 \
366
327k
      result = __real_##name arguments;                                        \
367
327k
    }                                                                          \
368
327k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
327k
                   zero_is_non_error);                                         \
370
327k
    return result;                                                             \
371
327k
  }                                                                            \
__wrap_SSL_write_ex
Line
Count
Source
358
278k
      ->decltype(__real_##name arguments) {                                    \
359
278k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
278k
    CheckUsable(ssl, #name);                                                   \
363
278k
    decltype(__real_##name arguments) result;                                  \
364
278k
    {                                                                          \
365
278k
      RealCallScope real_call;                                                 \
366
278k
      result = __real_##name arguments;                                        \
367
278k
    }                                                                          \
368
278k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
278k
                   zero_is_non_error);                                         \
370
278k
    return result;                                                             \
371
278k
  }                                                                            \
Unexecuted instantiation: __wrap_SSL_write_ex2
Unexecuted instantiation: __wrap_SSL_write_early_data
__wrap_SSL_shutdown
Line
Count
Source
358
130k
      ->decltype(__real_##name arguments) {                                    \
359
130k
    if (IsRealCallActive()) {                                                  \
360
0
      return __real_##name arguments;                                          \
361
0
    }                                                                          \
362
130k
    CheckUsable(ssl, #name);                                                   \
363
130k
    decltype(__real_##name arguments) result;                                  \
364
130k
    {                                                                          \
365
130k
      RealCallScope real_call;                                                 \
366
130k
      result = __real_##name arguments;                                        \
367
130k
    }                                                                          \
368
130k
    RecordIoResult(ssl, #name, static_cast<long long>(result),                 \
369
130k
                   zero_is_non_error);                                         \
370
130k
    return result;                                                             \
371
130k
  }                                                                            \
Unexecuted instantiation: __wrap_SSL_shutdown_ex
372
  static_assert(std::is_same<decltype(name), decltype(__wrap_##name)>::value,  \
373
                #name " signature changed");
374
375
#define DEFINE_IO_WRAPPER(name, parameters, arguments)                         \
376
  DEFINE_IO_WRAPPER_WITH_POLICY(name, parameters, arguments, false)
377
378
#define DEFINE_ZERO_NONERROR_WRAPPER(name, parameters, arguments)              \
379
  DEFINE_IO_WRAPPER_WITH_POLICY(name, parameters, arguments, true)
380
381
DEFINE_IO_WRAPPER(SSL_accept, (SSL * ssl), (ssl))
382
DEFINE_IO_WRAPPER(SSL_connect, (SSL * ssl), (ssl))
383
DEFINE_IO_WRAPPER(SSL_do_handshake, (SSL * ssl), (ssl))
384
DEFINE_IO_WRAPPER(SSL_read, (SSL * ssl, void *buffer, int length),
385
                  (ssl, buffer, length))
386
DEFINE_IO_WRAPPER(SSL_read_ex,
387
                  (SSL * ssl, void *buffer, size_t length, size_t *readbytes),
388
                  (ssl, buffer, length, readbytes))
389
DEFINE_IO_WRAPPER(SSL_read_early_data,
390
                  (SSL * ssl, void *buffer, size_t length, size_t *readbytes),
391
                  (ssl, buffer, length, readbytes))
392
DEFINE_IO_WRAPPER(SSL_peek, (SSL * ssl, void *buffer, int length),
393
                  (ssl, buffer, length))
394
DEFINE_IO_WRAPPER(SSL_peek_ex,
395
                  (SSL * ssl, void *buffer, size_t length, size_t *readbytes),
396
                  (ssl, buffer, length, readbytes))
397
DEFINE_ZERO_NONERROR_WRAPPER(SSL_sendfile,
398
                             (SSL * ssl, int fd, off_t offset, size_t size,
399
                              int flags),
400
                             (ssl, fd, offset, size, flags))
401
DEFINE_IO_WRAPPER(SSL_write, (SSL * ssl, const void *buffer, int length),
402
                  (ssl, buffer, length))
403
DEFINE_IO_WRAPPER(SSL_write_ex,
404
                  (SSL * ssl, const void *buffer, size_t length,
405
                   size_t *written),
406
                  (ssl, buffer, length, written))
407
DEFINE_IO_WRAPPER(SSL_write_ex2,
408
                  (SSL * ssl, const void *buffer, size_t length, uint64_t flags,
409
                   size_t *written),
410
                  (ssl, buffer, length, flags, written))
411
DEFINE_IO_WRAPPER(SSL_write_early_data,
412
                  (SSL * ssl, const void *buffer, size_t length,
413
                   size_t *written),
414
                  (ssl, buffer, length, written))
415
DEFINE_ZERO_NONERROR_WRAPPER(SSL_shutdown, (SSL * ssl), (ssl))
416
DEFINE_ZERO_NONERROR_WRAPPER(SSL_shutdown_ex,
417
                             (SSL * ssl, uint64_t flags,
418
                              const SSL_SHUTDOWN_EX_ARGS *args,
419
                              size_t args_length),
420
                             (ssl, flags, args, args_length))
421
422
#undef DEFINE_ZERO_NONERROR_WRAPPER
423
#undef DEFINE_IO_WRAPPER
424
#undef DEFINE_IO_WRAPPER_WITH_POLICY