Coverage Report

Created: 2025-06-13 06:58

/src/openssl31/crypto/threads_pthread.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2016-2023 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
/* We need to use the OPENSSL_fork_*() deprecated APIs */
11
#define OPENSSL_SUPPRESS_DEPRECATED
12
13
#include <openssl/crypto.h>
14
#include "internal/cryptlib.h"
15
16
#if defined(__sun)
17
# include <atomic.h>
18
#endif
19
20
#if defined(__apple_build_version__) && __apple_build_version__ < 6000000
21
/*
22
 * OS/X 10.7 and 10.8 had a weird version of clang which has __ATOMIC_ACQUIRE and
23
 * __ATOMIC_ACQ_REL but which expects only one parameter for __atomic_is_lock_free()
24
 * rather than two which has signature __atomic_is_lock_free(sizeof(_Atomic(T))).
25
 * All of this makes impossible to use __atomic_is_lock_free here.
26
 *
27
 * See: https://github.com/llvm/llvm-project/commit/a4c2602b714e6c6edb98164550a5ae829b2de760
28
 */
29
#define BROKEN_CLANG_ATOMICS
30
#endif
31
32
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
33
34
# if defined(OPENSSL_SYS_UNIX)
35
#  include <sys/types.h>
36
#  include <unistd.h>
37
#endif
38
39
# include <assert.h>
40
41
# ifdef PTHREAD_RWLOCK_INITIALIZER
42
#  define USE_RWLOCK
43
# endif
44
45
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
46
12.4M
{
47
12.4M
# ifdef USE_RWLOCK
48
12.4M
    CRYPTO_RWLOCK *lock;
49
50
12.4M
    if ((lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t))) == NULL) {
51
        /* Don't set error, to avoid recursion blowup. */
52
0
        return NULL;
53
0
    }
54
55
12.4M
    if (pthread_rwlock_init(lock, NULL) != 0) {
56
0
        OPENSSL_free(lock);
57
0
        return NULL;
58
0
    }
59
# else
60
    pthread_mutexattr_t attr;
61
    CRYPTO_RWLOCK *lock;
62
63
    if ((lock = OPENSSL_zalloc(sizeof(pthread_mutex_t))) == NULL) {
64
        /* Don't set error, to avoid recursion blowup. */
65
        return NULL;
66
    }
67
68
    /*
69
     * We don't use recursive mutexes, but try to catch errors if we do.
70
     */
71
    pthread_mutexattr_init(&attr);
72
#  if !defined (__TANDEM) && !defined (_SPT_MODEL_)
73
#   if !defined(NDEBUG) && !defined(OPENSSL_NO_MUTEX_ERRORCHECK)
74
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
75
#   endif
76
#  else
77
    /* The SPT Thread Library does not define MUTEX attributes. */
78
#  endif
79
80
    if (pthread_mutex_init(lock, &attr) != 0) {
81
        pthread_mutexattr_destroy(&attr);
82
        OPENSSL_free(lock);
83
        return NULL;
84
    }
85
86
    pthread_mutexattr_destroy(&attr);
87
# endif
88
89
12.4M
    return lock;
90
12.4M
}
91
92
__owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
93
1.12G
{
94
1.12G
# ifdef USE_RWLOCK
95
1.12G
    if (pthread_rwlock_rdlock(lock) != 0)
96
0
        return 0;
97
# else
98
    if (pthread_mutex_lock(lock) != 0) {
99
        assert(errno != EDEADLK && errno != EBUSY);
100
        return 0;
101
    }
102
# endif
103
104
1.12G
    return 1;
105
1.12G
}
106
107
__owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
108
45.1M
{
109
45.1M
# ifdef USE_RWLOCK
110
45.1M
    if (pthread_rwlock_wrlock(lock) != 0)
111
0
        return 0;
112
# else
113
    if (pthread_mutex_lock(lock) != 0) {
114
        assert(errno != EDEADLK && errno != EBUSY);
115
        return 0;
116
    }
117
# endif
118
119
45.1M
    return 1;
120
45.1M
}
121
122
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
123
1.21G
{
124
1.21G
# ifdef USE_RWLOCK
125
1.21G
    if (pthread_rwlock_unlock(lock) != 0)
126
0
        return 0;
127
# else
128
    if (pthread_mutex_unlock(lock) != 0) {
129
        assert(errno != EPERM);
130
        return 0;
131
    }
132
# endif
133
134
1.21G
    return 1;
135
1.21G
}
136
137
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
138
12.4M
{
139
12.4M
    if (lock == NULL)
140
1.02k
        return;
141
142
12.4M
# ifdef USE_RWLOCK
143
12.4M
    pthread_rwlock_destroy(lock);
144
# else
145
    pthread_mutex_destroy(lock);
146
# endif
147
12.4M
    OPENSSL_free(lock);
148
149
12.4M
    return;
150
12.4M
}
151
152
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
153
1.81G
{
154
1.81G
    if (pthread_once(once, init) != 0)
155
0
        return 0;
156
157
1.81G
    return 1;
158
1.81G
}
159
160
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
161
991
{
162
991
    if (pthread_key_create(key, cleanup) != 0)
163
0
        return 0;
164
165
991
    return 1;
166
991
}
167
168
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
169
939M
{
170
939M
    return pthread_getspecific(*key);
171
939M
}
172
173
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
174
1.04k
{
175
1.04k
    if (pthread_setspecific(*key, val) != 0)
176
0
        return 0;
177
178
1.04k
    return 1;
179
1.04k
}
180
181
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
182
859
{
183
859
    if (pthread_key_delete(*key) != 0)
184
0
        return 0;
185
186
859
    return 1;
187
859
}
188
189
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
190
104k
{
191
104k
    return pthread_self();
192
104k
}
193
194
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
195
8.87k
{
196
8.87k
    return pthread_equal(a, b);
197
8.87k
}
198
199
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
200
4.28M
{
201
4.28M
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
202
4.28M
    if (__atomic_is_lock_free(sizeof(*val), val)) {
203
4.28M
        *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
204
4.28M
        return 1;
205
4.28M
    }
206
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
207
    /* This will work for all future Solaris versions. */
208
    if (ret != NULL) {
209
        *ret = atomic_add_int_nv((volatile unsigned int *)val, amount);
210
        return 1;
211
    }
212
# endif
213
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
214
0
        return 0;
215
216
0
    *val += amount;
217
0
    *ret  = *val;
218
219
0
    if (!CRYPTO_THREAD_unlock(lock))
220
0
        return 0;
221
222
0
    return 1;
223
0
}
224
225
int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
226
                     CRYPTO_RWLOCK *lock)
227
318
{
228
318
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
229
318
    if (__atomic_is_lock_free(sizeof(*val), val)) {
230
318
        *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL);
231
318
        return 1;
232
318
    }
233
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
234
    /* This will work for all future Solaris versions. */
235
    if (ret != NULL) {
236
        *ret = atomic_or_64_nv(val, op);
237
        return 1;
238
    }
239
# endif
240
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
241
0
        return 0;
242
0
    *val |= op;
243
0
    *ret  = *val;
244
245
0
    if (!CRYPTO_THREAD_unlock(lock))
246
0
        return 0;
247
248
0
    return 1;
249
0
}
250
251
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
252
1.31G
{
253
1.31G
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
254
1.31G
    if (__atomic_is_lock_free(sizeof(*val), val)) {
255
1.31G
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
256
1.31G
        return 1;
257
1.31G
    }
258
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
259
    /* This will work for all future Solaris versions. */
260
    if (ret != NULL) {
261
        *ret = atomic_or_64_nv(val, 0);
262
        return 1;
263
    }
264
# endif
265
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
266
0
        return 0;
267
0
    *ret  = *val;
268
0
    if (!CRYPTO_THREAD_unlock(lock))
269
0
        return 0;
270
271
0
    return 1;
272
0
}
273
# ifndef FIPS_MODULE
274
int openssl_init_fork_handlers(void)
275
0
{
276
0
    return 1;
277
0
}
278
# endif /* FIPS_MODULE */
279
280
int openssl_get_fork_id(void)
281
81.8k
{
282
81.8k
    return getpid();
283
81.8k
}
284
#endif