Coverage Report

Created: 2026-05-20 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/async/async_local.h
Line
Count
Source
1
/*
2
 * Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
/*
11
 * Must do this before including any header files, because on MacOS/X <stlib.h>
12
 * includes <signal.h> which includes <ucontext.h>
13
 */
14
#if !defined(OSSL_LIBCRYPTO_ASYNC_ASYNC_LOCAL_H)
15
#define OSSL_LIBCRYPTO_ASYNC_ASYNC_LOCAL_H
16
17
#if defined(__APPLE__) && defined(__MACH__) && !defined(_XOPEN_SOURCE)
18
#define _XOPEN_SOURCE /* Otherwise incomplete ucontext_t structure */
19
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
20
#endif
21
22
#include <openssl/crypto.h>
23
#include <openssl/e_os2.h>
24
25
typedef struct async_ctx_st async_ctx;
26
typedef struct async_pool_st async_pool;
27
28
#if defined(_WIN32)
29
#define ASYNC_WIN
30
#define ASYNC_ARCH
31
32
#include <windows.h>
33
#include "internal/cryptlib.h"
34
35
typedef struct async_fibre_st {
36
    LPVOID fibre;
37
    int converted;
38
} async_fibre;
39
40
#define async_fibre_swapcontext(o, n, r) \
41
    (SwitchToFiber((n)->fibre), 1)
42
43
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
44
#define async_fibre_makecontext(c)                             \
45
    ((c)->fibre = CreateFiberEx(0, 0, FIBER_FLAG_FLOAT_SWITCH, \
46
         async_start_func_win, 0))
47
#else
48
#define async_fibre_makecontext(c) \
49
    ((c)->fibre = CreateFiber(0, async_start_func_win, 0))
50
#endif
51
52
#define async_fibre_free(f) (DeleteFiber((f)->fibre))
53
#define async_local_init() 1
54
#define async_local_deinit()
55
56
int async_fibre_init_dispatcher(async_fibre *fibre);
57
VOID CALLBACK async_start_func_win(PVOID unused);
58
59
#elif defined(OPENSSL_SYS_UNIX)                               \
60
    && defined(OPENSSL_THREADS) && !defined(OPENSSL_NO_ASYNC) \
61
    && !defined(__ANDROID__) && !defined(__OpenBSD__)         \
62
    && !defined(OPENSSL_SYS_TANDEM)
63
64
#include <unistd.h>
65
66
#if _POSIX_VERSION >= 200112L \
67
    && (_POSIX_VERSION < 200809L || defined(__GLIBC__) || defined(__FreeBSD__))
68
69
#include <pthread.h>
70
71
#define ASYNC_POSIX
72
#define ASYNC_ARCH
73
74
#if defined(__CET__) || defined(__ia64__)
75
/*
76
 * When Intel CET is enabled, makecontext will create a different
77
 * shadow stack for each context.  async_fibre_swapcontext cannot
78
 * use _longjmp.  It must call swapcontext to swap shadow stack as
79
 * well as normal stack.
80
 * On IA64 the register stack engine is not saved across setjmp/longjmp. Here
81
 * swapcontext() performs correctly.
82
 */
83
#define USE_SWAPCONTEXT
84
#endif
85
#if defined(__aarch64__) && defined(__clang__) \
86
    && defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
87
/*
88
 * setjmp/longjmp don't currently work with BTI on all libc implementations
89
 * when compiled by clang. This is because clang doesn't put a BTI after the
90
 * call to setjmp where it returns the second time. This then fails on libc
91
 * implementations - notably glibc - which use an indirect jump to there.
92
 * So use the swapcontext implementation, which does work.
93
 * See https://github.com/llvm/llvm-project/issues/48888.
94
 */
95
#define USE_SWAPCONTEXT
96
#endif
97
#include <ucontext.h>
98
#ifndef USE_SWAPCONTEXT
99
#include <setjmp.h>
100
#endif
101
102
typedef struct async_fibre_st {
103
    ucontext_t fibre;
104
#ifndef USE_SWAPCONTEXT
105
    jmp_buf env;
106
    int env_init;
107
#endif
108
} async_fibre;
109
110
int async_local_init(void);
111
void async_local_deinit(void);
112
113
static ossl_inline int async_fibre_swapcontext(async_fibre *o, async_fibre *n, int r)
114
0
{
115
#ifdef USE_SWAPCONTEXT
116
    swapcontext(&o->fibre, &n->fibre);
117
#else
118
0
    o->env_init = 1;
119
120
0
    if (!r || !_setjmp(o->env)) {
121
0
        if (n->env_init)
122
0
            _longjmp(n->env, 1);
123
0
        else
124
0
            setcontext(&n->fibre);
125
0
    }
126
0
#endif
127
128
0
    return 1;
129
0
}
Unexecuted instantiation: async.c:async_fibre_swapcontext
Unexecuted instantiation: async_wait.c:async_fibre_swapcontext
Unexecuted instantiation: async_posix.c:async_fibre_swapcontext
130
131
#define async_fibre_init_dispatcher(d)
132
133
int async_fibre_makecontext(async_fibre *fibre);
134
void async_fibre_free(async_fibre *fibre);
135
136
#endif
137
#endif /* UNIX */
138
139
#ifndef ASYNC_ARCH
140
#define ASYNC_NULL
141
#define ASYNC_ARCH
142
143
typedef struct async_fibre_st {
144
    int dummy;
145
} async_fibre;
146
147
#define async_fibre_swapcontext(o, n, r) 0
148
#define async_fibre_makecontext(c) 0
149
#define async_fibre_free(f)
150
#define async_fibre_init_dispatcher(f)
151
#define async_local_init() 1
152
#define async_local_deinit()
153
#endif
154
155
/* needs to be included after windows.h */
156
#include <openssl/async.h>
157
#include "crypto/async.h"
158
159
struct async_ctx_st {
160
    async_fibre dispatcher;
161
    ASYNC_JOB *currjob;
162
    unsigned int blocked;
163
};
164
165
struct async_job_st {
166
    async_fibre fibrectx;
167
    int (*func)(void *);
168
    void *funcargs;
169
    int ret;
170
    int status;
171
    ASYNC_WAIT_CTX *waitctx;
172
    OSSL_LIB_CTX *libctx;
173
};
174
175
struct fd_lookup_st {
176
    const void *key;
177
    OSSL_ASYNC_FD fd;
178
    void *custom_data;
179
    void (*cleanup)(ASYNC_WAIT_CTX *, const void *, OSSL_ASYNC_FD, void *);
180
    int add;
181
    int del;
182
    struct fd_lookup_st *next;
183
};
184
185
struct async_wait_ctx_st {
186
    struct fd_lookup_st *fds;
187
    size_t numadd;
188
    size_t numdel;
189
    ASYNC_callback_fn callback;
190
    void *callback_arg;
191
    int status;
192
};
193
194
DEFINE_STACK_OF(ASYNC_JOB)
195
196
struct async_pool_st {
197
    STACK_OF(ASYNC_JOB) *jobs;
198
    size_t curr_size;
199
    size_t max_size;
200
};
201
202
void async_local_cleanup(void);
203
void async_start_func(void);
204
async_ctx *async_get_ctx(void);
205
206
void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx);
207
208
#endif /* !defined(OSSL_LIBCRYPTO_ASYNC_ASYNC_LOCAL_H) */