Coverage Report

Created: 2025-11-16 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl32/crypto/threads_pthread.c
Line
Count
Source
1
/*
2
 * Copyright 2016-2025 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
/*
42
 * The Non-Stop KLT thread model currently seems broken in its rwlock
43
 * implementation
44
 * Likewise is there a problem with the glibc implementation on riscv.
45
 */
46
# if defined(PTHREAD_RWLOCK_INITIALIZER) && !defined(_KLT_MODEL_) \
47
                                         && !defined(__riscv)
48
#  define USE_RWLOCK
49
# endif
50
51
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
52
9.94M
{
53
9.94M
# ifdef USE_RWLOCK
54
9.94M
    CRYPTO_RWLOCK *lock;
55
56
9.94M
    if ((lock = CRYPTO_zalloc(sizeof(pthread_rwlock_t), NULL, 0)) == NULL)
57
        /* Don't set error, to avoid recursion blowup. */
58
0
        return NULL;
59
60
9.94M
    if (pthread_rwlock_init(lock, NULL) != 0) {
61
0
        OPENSSL_free(lock);
62
0
        return NULL;
63
0
    }
64
# else
65
    pthread_mutexattr_t attr;
66
    CRYPTO_RWLOCK *lock;
67
68
    if ((lock = CRYPTO_zalloc(sizeof(pthread_mutex_t), NULL, 0)) == NULL)
69
        /* Don't set error, to avoid recursion blowup. */
70
        return NULL;
71
72
    /*
73
     * We don't use recursive mutexes, but try to catch errors if we do.
74
     */
75
    pthread_mutexattr_init(&attr);
76
#  if !defined (__TANDEM) && !defined (_SPT_MODEL_)
77
#   if !defined(NDEBUG) && !defined(OPENSSL_NO_MUTEX_ERRORCHECK)
78
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
79
#   endif
80
#  else
81
    /* The SPT Thread Library does not define MUTEX attributes. */
82
#  endif
83
84
    if (pthread_mutex_init(lock, &attr) != 0) {
85
        pthread_mutexattr_destroy(&attr);
86
        OPENSSL_free(lock);
87
        return NULL;
88
    }
89
90
    pthread_mutexattr_destroy(&attr);
91
# endif
92
93
9.94M
    return lock;
94
9.94M
}
95
96
__owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
97
1.09G
{
98
1.09G
# ifdef USE_RWLOCK
99
1.09G
    if (pthread_rwlock_rdlock(lock) != 0)
100
0
        return 0;
101
# else
102
    if (pthread_mutex_lock(lock) != 0) {
103
        assert(errno != EDEADLK && errno != EBUSY);
104
        return 0;
105
    }
106
# endif
107
108
1.09G
    return 1;
109
1.09G
}
110
111
__owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
112
77.7M
{
113
77.7M
# ifdef USE_RWLOCK
114
77.7M
    if (pthread_rwlock_wrlock(lock) != 0)
115
0
        return 0;
116
# else
117
    if (pthread_mutex_lock(lock) != 0) {
118
        assert(errno != EDEADLK && errno != EBUSY);
119
        return 0;
120
    }
121
# endif
122
123
77.7M
    return 1;
124
77.7M
}
125
126
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
127
1.26G
{
128
1.26G
# ifdef USE_RWLOCK
129
1.26G
    if (pthread_rwlock_unlock(lock) != 0)
130
0
        return 0;
131
# else
132
    if (pthread_mutex_unlock(lock) != 0) {
133
        assert(errno != EPERM);
134
        return 0;
135
    }
136
# endif
137
138
1.26G
    return 1;
139
1.26G
}
140
141
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
142
9.94M
{
143
9.94M
    if (lock == NULL)
144
2.20k
        return;
145
146
9.94M
# ifdef USE_RWLOCK
147
9.94M
    pthread_rwlock_destroy(lock);
148
# else
149
    pthread_mutex_destroy(lock);
150
# endif
151
9.94M
    OPENSSL_free(lock);
152
153
9.94M
    return;
154
9.94M
}
155
156
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
157
2.92G
{
158
2.92G
    if (pthread_once(once, init) != 0)
159
0
        return 0;
160
161
2.92G
    return 1;
162
2.92G
}
163
164
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
165
1.89k
{
166
1.89k
    if (pthread_key_create(key, cleanup) != 0)
167
0
        return 0;
168
169
1.89k
    return 1;
170
1.89k
}
171
172
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
173
1.83G
{
174
1.83G
    return pthread_getspecific(*key);
175
1.83G
}
176
177
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
178
1.91k
{
179
1.91k
    if (pthread_setspecific(*key, val) != 0)
180
0
        return 0;
181
182
1.91k
    return 1;
183
1.91k
}
184
185
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
186
1.57k
{
187
1.57k
    if (pthread_key_delete(*key) != 0)
188
0
        return 0;
189
190
1.57k
    return 1;
191
1.57k
}
192
193
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
194
183k
{
195
183k
    return pthread_self();
196
183k
}
197
198
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
199
11.8k
{
200
11.8k
    return pthread_equal(a, b);
201
11.8k
}
202
203
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
204
10.9M
{
205
10.9M
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
206
10.9M
    if (__atomic_is_lock_free(sizeof(*val), val)) {
207
10.9M
        *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
208
10.9M
        return 1;
209
10.9M
    }
210
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
211
    /* This will work for all future Solaris versions. */
212
    if (ret != NULL) {
213
        *ret = atomic_add_int_nv((volatile unsigned int *)val, amount);
214
        return 1;
215
    }
216
# endif
217
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
218
0
        return 0;
219
220
0
    *val += amount;
221
0
    *ret  = *val;
222
223
0
    if (!CRYPTO_THREAD_unlock(lock))
224
0
        return 0;
225
226
0
    return 1;
227
0
}
228
229
int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
230
                     CRYPTO_RWLOCK *lock)
231
644
{
232
644
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
233
644
    if (__atomic_is_lock_free(sizeof(*val), val)) {
234
644
        *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL);
235
644
        return 1;
236
644
    }
237
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
238
    /* This will work for all future Solaris versions. */
239
    if (ret != NULL) {
240
        *ret = atomic_or_64_nv(val, op);
241
        return 1;
242
    }
243
# endif
244
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
245
0
        return 0;
246
0
    *val |= op;
247
0
    *ret  = *val;
248
249
0
    if (!CRYPTO_THREAD_unlock(lock))
250
0
        return 0;
251
252
0
    return 1;
253
0
}
254
255
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
256
2.43G
{
257
2.43G
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
258
2.43G
    if (__atomic_is_lock_free(sizeof(*val), val)) {
259
2.43G
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
260
2.43G
        return 1;
261
2.43G
    }
262
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
263
    /* This will work for all future Solaris versions. */
264
    if (ret != NULL) {
265
        *ret = atomic_or_64_nv(val, 0);
266
        return 1;
267
    }
268
# endif
269
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
270
0
        return 0;
271
0
    *ret  = *val;
272
0
    if (!CRYPTO_THREAD_unlock(lock))
273
0
        return 0;
274
275
0
    return 1;
276
0
}
277
278
int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
279
0
{
280
0
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
281
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
282
0
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
283
0
        return 1;
284
0
    }
285
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
286
    /* This will work for all future Solaris versions. */
287
    if (ret != NULL) {
288
        *ret = (int *)atomic_or_uint_nv((unsigned int *)val, 0);
289
        return 1;
290
    }
291
# endif
292
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
293
0
        return 0;
294
0
    *ret  = *val;
295
0
    if (!CRYPTO_THREAD_unlock(lock))
296
0
        return 0;
297
298
0
    return 1;
299
0
}
300
301
# ifndef FIPS_MODULE
302
int openssl_init_fork_handlers(void)
303
0
{
304
0
    return 1;
305
0
}
306
# endif /* FIPS_MODULE */
307
308
int openssl_get_fork_id(void)
309
74.8k
{
310
74.8k
    return getpid();
311
74.8k
}
312
#endif