Coverage Report

Created: 2023-06-08 06:40

/src/openssl30/crypto/threads_pthread.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2016-2022 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
3.47k
{
47
3.47k
# ifdef USE_RWLOCK
48
3.47k
    CRYPTO_RWLOCK *lock;
49
50
3.47k
    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
3.47k
    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
#   else
76
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
77
#   endif
78
#  else
79
    /* The SPT Thread Library does not define MUTEX attributes. */
80
#  endif
81
82
    if (pthread_mutex_init(lock, &attr) != 0) {
83
        pthread_mutexattr_destroy(&attr);
84
        OPENSSL_free(lock);
85
        return NULL;
86
    }
87
88
    pthread_mutexattr_destroy(&attr);
89
# endif
90
91
3.47k
    return lock;
92
3.47k
}
93
94
__owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
95
198
{
96
198
# ifdef USE_RWLOCK
97
198
    if (pthread_rwlock_rdlock(lock) != 0)
98
0
        return 0;
99
# else
100
    if (pthread_mutex_lock(lock) != 0) {
101
        assert(errno != EDEADLK && errno != EBUSY);
102
        return 0;
103
    }
104
# endif
105
106
198
    return 1;
107
198
}
108
109
__owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
110
7.09k
{
111
7.09k
# ifdef USE_RWLOCK
112
7.09k
    if (pthread_rwlock_wrlock(lock) != 0)
113
0
        return 0;
114
# else
115
    if (pthread_mutex_lock(lock) != 0) {
116
        assert(errno != EDEADLK && errno != EBUSY);
117
        return 0;
118
    }
119
# endif
120
121
7.09k
    return 1;
122
7.09k
}
123
124
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
125
7.29k
{
126
7.29k
# ifdef USE_RWLOCK
127
7.29k
    if (pthread_rwlock_unlock(lock) != 0)
128
0
        return 0;
129
# else
130
    if (pthread_mutex_unlock(lock) != 0) {
131
        assert(errno != EPERM);
132
        return 0;
133
    }
134
# endif
135
136
7.29k
    return 1;
137
7.29k
}
138
139
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
140
3.48k
{
141
3.48k
    if (lock == NULL)
142
10
        return;
143
144
3.47k
# ifdef USE_RWLOCK
145
3.47k
    pthread_rwlock_destroy(lock);
146
# else
147
    pthread_mutex_destroy(lock);
148
# endif
149
3.47k
    OPENSSL_free(lock);
150
151
3.47k
    return;
152
3.48k
}
153
154
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
155
49.8k
{
156
49.8k
    if (pthread_once(once, init) != 0)
157
0
        return 0;
158
159
49.8k
    return 1;
160
49.8k
}
161
162
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
163
8
{
164
8
    if (pthread_key_create(key, cleanup) != 0)
165
0
        return 0;
166
167
8
    return 1;
168
8
}
169
170
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
171
28.2k
{
172
28.2k
    return pthread_getspecific(*key);
173
28.2k
}
174
175
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
176
10
{
177
10
    if (pthread_setspecific(*key, val) != 0)
178
0
        return 0;
179
180
10
    return 1;
181
10
}
182
183
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
184
8
{
185
8
    if (pthread_key_delete(*key) != 0)
186
0
        return 0;
187
188
8
    return 1;
189
8
}
190
191
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
192
0
{
193
0
    return pthread_self();
194
0
}
195
196
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
197
0
{
198
0
    return pthread_equal(a, b);
199
0
}
200
201
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
202
0
{
203
0
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
204
0
    if (__atomic_is_lock_free(sizeof(*val), val)) {
205
0
        *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
206
0
        return 1;
207
0
    }
208
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
209
    /* This will work for all future Solaris versions. */
210
    if (ret != NULL) {
211
        *ret = atomic_add_int_nv((volatile unsigned int *)val, amount);
212
        return 1;
213
    }
214
# endif
215
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
216
0
        return 0;
217
218
0
    *val += amount;
219
0
    *ret  = *val;
220
221
0
    if (!CRYPTO_THREAD_unlock(lock))
222
0
        return 0;
223
224
0
    return 1;
225
0
}
226
227
int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
228
                     CRYPTO_RWLOCK *lock)
229
2
{
230
2
# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
231
2
    if (__atomic_is_lock_free(sizeof(*val), val)) {
232
2
        *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL);
233
2
        return 1;
234
2
    }
235
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
236
    /* This will work for all future Solaris versions. */
237
    if (ret != NULL) {
238
        *ret = atomic_or_64_nv(val, op);
239
        return 1;
240
    }
241
# endif
242
0
    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
243
0
        return 0;
244
0
    *val |= op;
245
0
    *ret  = *val;
246
247
0
    if (!CRYPTO_THREAD_unlock(lock))
248
0
        return 0;
249
250
0
    return 1;
251
0
}
252
253
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
254
21.4k
{
255
21.4k
# if defined(__GNUC__) && defined(__ATOMIC_ACQUIRE) && !defined(BROKEN_CLANG_ATOMICS)
256
21.4k
    if (__atomic_is_lock_free(sizeof(*val), val)) {
257
21.4k
        __atomic_load(val, ret, __ATOMIC_ACQUIRE);
258
21.4k
        return 1;
259
21.4k
    }
260
# elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
261
    /* This will work for all future Solaris versions. */
262
    if (ret != NULL) {
263
        *ret = atomic_or_64_nv(val, 0);
264
        return 1;
265
    }
266
# endif
267
0
    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
268
0
        return 0;
269
0
    *ret  = *val;
270
0
    if (!CRYPTO_THREAD_unlock(lock))
271
0
        return 0;
272
273
0
    return 1;
274
0
}
275
# ifndef FIPS_MODULE
276
int openssl_init_fork_handlers(void)
277
0
{
278
0
    return 1;
279
0
}
280
# endif /* FIPS_MODULE */
281
282
int openssl_get_fork_id(void)
283
0
{
284
0
    return getpid();
285
0
}
286
#endif