Bug Summary

File:src/lib/libc/thread/rthread_libc.c
Warning:line 107, column 28
Access to field 'k' results in a dereference of a null pointer (loaded from variable 'tt')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name rthread_libc.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libc/obj -resource-dir /usr/local/lib/clang/13.0.0 -include namespace.h -I /usr/src/lib/libc/include -I /usr/src/lib/libc/hidden -D __LIBC__ -D APIWARN -D YP -I /usr/src/lib/libc/yp -I /usr/src/lib/libc -I /usr/src/lib/libc/gdtoa -I /usr/src/lib/libc/arch/amd64/gdtoa -D INFNAN_CHECK -D MULTIPLE_THREADS -D NO_FENV_H -D USE_LOCALE -I /usr/src/lib/libc -I /usr/src/lib/libc/citrus -D RESOLVSORT -D FLOATING_POINT -D PRINTF_WIDE_CHAR -D SCANF_WIDE_CHAR -D FUTEX -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libc/thread/rthread_libc.c
1/* $OpenBSD: rthread_libc.c,v 1.4 2021/01/06 19:54:17 otto Exp $ */
2
3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4
5#include <pthread.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "rthread.h"
10#include "rthread_cb.h"
11
12/*
13 * A thread tag is a pointer to a structure of this type. An opaque
14 * tag is used to decouple libc from the thread library.
15 */
16struct _thread_tag {
17 pthread_mutex_t m; /* the tag's mutex */
18 pthread_key_t k; /* a key for private data */
19};
20
21/*
22 * local mutex to protect against tag creation races.
23 */
24static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER((void *)0);
25
26/*
27 * Initialize a thread tag structure once. This function is called
28 * if the tag is null. Allocation and initialization are controlled
29 * by a mutex. If the tag is not null when the mutex is obtained
30 * the caller lost a race -- some other thread initialized the tag.
31 * This function will never return NULL.
32 */
33static void
34_thread_tag_init(void **tag, void (*dt)(void *))
35{
36 struct _thread_tag *tt;
37 int result;
38
39 result = pthread_mutex_lock(&_thread_tag_mutex);
40 if (result == 0) {
41 if (*tag == NULL((void *)0)) {
42 tt = malloc(sizeof *tt);
43 if (tt != NULL((void *)0)) {
44 result = pthread_mutex_init(&tt->m, NULL((void *)0));
45 result |= pthread_key_create(&tt->k, dt ? dt :
46 free);
47 *tag = tt;
48 }
49 }
50 result |= pthread_mutex_unlock(&_thread_tag_mutex);
51 }
52 if (result != 0)
53 _rthread_debug(1, "tag init failure");
54}
55
56/*
57 * lock the mutex associated with the given tag
58 */
59void
60_thread_tag_lock(void **tag)
61{
62 struct _thread_tag *tt;
63
64 if (__isthreaded) {
65 if (*tag == NULL((void *)0))
66 _thread_tag_init(tag, NULL((void *)0));
67 tt = *tag;
68 if (pthread_mutex_lock(&tt->m) != 0)
69 _rthread_debug(1, "tag mutex lock failure");
70 }
71}
72
73/*
74 * unlock the mutex associated with the given tag
75 */
76void
77_thread_tag_unlock(void **tag)
78{
79 struct _thread_tag *tt;
80
81 if (__isthreaded) {
82 if (*tag == NULL((void *)0))
83 _thread_tag_init(tag, NULL((void *)0));
84 tt = *tag;
85 if (pthread_mutex_unlock(&tt->m) != 0)
86 _rthread_debug(1, "tag mutex unlock failure");
87 }
88}
89
90/*
91 * return the thread specific data for the given tag. If there
92 * is no data for this thread allocate and initialize it from 'storage'
93 * or clear it for non-main threads.
94 * On any error return 'err'.
95 */
96void *
97_thread_tag_storage(void **tag, void *storage, size_t sz, void (*dt)(void *),
98 void *err)
99{
100 struct _thread_tag *tt;
101 void *ret;
102
103 if (*tag == NULL((void *)0))
1
Assuming pointer value is null
2
Taking true branch
104 _thread_tag_init(tag, dt);
105 tt = *tag;
3
Null pointer value stored to 'tt'
106
107 ret = pthread_getspecific(tt->k);
4
Access to field 'k' results in a dereference of a null pointer (loaded from variable 'tt')
108 if (ret == NULL((void *)0)) {
109 ret = calloc(1, sz);
110 if (ret == NULL((void *)0))
111 ret = err;
112 else {
113 if (pthread_setspecific(tt->k, ret) == 0) {
114 if (pthread_self() == &_initial_thread)
115 memcpy(ret, storage, sz);
116 } else {
117 free(ret);
118 ret = err;
119 }
120 }
121 }
122 return ret;
123}
124
125void
126_thread_mutex_lock(void **mutex)
127{
128 pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex;
129
130 if (pthread_mutex_lock(pmutex) != 0)
131 _rthread_debug(1, "mutex lock failure");
132}
133
134void
135_thread_mutex_unlock(void **mutex)
136{
137 pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex;
138
139 if (pthread_mutex_unlock(pmutex) != 0)
140 _rthread_debug(1, "mutex unlock failure");
141}
142
143void
144_thread_mutex_destroy(void **mutex)
145{
146 pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex;
147
148 if (pthread_mutex_destroy(pmutex) != 0)
149 _rthread_debug(1, "mutex destroy failure");
150}
151
152/*
153 * the malloc lock
154 */
155#ifndef FUTEX1
156#define MALLOC_LOCK_INITIALIZER(n){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 } { \
157 _SPINLOCK_UNLOCKED(0), \
158 TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers){ ((void *)0), &(malloc_lock[n].lockers).tqh_first }, \
159 PTHREAD_MUTEX_DEFAULTPTHREAD_MUTEX_STRICT_NP, \
160 NULL((void *)0), \
161 0, \
162 -1 }
163#else
164#define MALLOC_LOCK_INITIALIZER(n){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 } { \
165 _SPINLOCK_UNLOCKED(0), \
166 PTHREAD_MUTEX_DEFAULTPTHREAD_MUTEX_STRICT_NP, \
167 NULL((void *)0), \
168 0, \
169 -1 }
170#endif
171
172static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES32] = {
173 MALLOC_LOCK_INITIALIZER(0){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
174 MALLOC_LOCK_INITIALIZER(1){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
175 MALLOC_LOCK_INITIALIZER(2){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
176 MALLOC_LOCK_INITIALIZER(3){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
177 MALLOC_LOCK_INITIALIZER(4){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
178 MALLOC_LOCK_INITIALIZER(5){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
179 MALLOC_LOCK_INITIALIZER(6){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
180 MALLOC_LOCK_INITIALIZER(7){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
181 MALLOC_LOCK_INITIALIZER(8){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
182 MALLOC_LOCK_INITIALIZER(9){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
183 MALLOC_LOCK_INITIALIZER(10){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
184 MALLOC_LOCK_INITIALIZER(11){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
185 MALLOC_LOCK_INITIALIZER(12){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
186 MALLOC_LOCK_INITIALIZER(13){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
187 MALLOC_LOCK_INITIALIZER(14){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
188 MALLOC_LOCK_INITIALIZER(15){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
189 MALLOC_LOCK_INITIALIZER(16){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
190 MALLOC_LOCK_INITIALIZER(17){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
191 MALLOC_LOCK_INITIALIZER(18){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
192 MALLOC_LOCK_INITIALIZER(19){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
193 MALLOC_LOCK_INITIALIZER(20){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
194 MALLOC_LOCK_INITIALIZER(21){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
195 MALLOC_LOCK_INITIALIZER(22){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
196 MALLOC_LOCK_INITIALIZER(23){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
197 MALLOC_LOCK_INITIALIZER(24){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
198 MALLOC_LOCK_INITIALIZER(25){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
199 MALLOC_LOCK_INITIALIZER(26){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
200 MALLOC_LOCK_INITIALIZER(27){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
201 MALLOC_LOCK_INITIALIZER(28){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
202 MALLOC_LOCK_INITIALIZER(29){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
203 MALLOC_LOCK_INITIALIZER(30){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 },
204 MALLOC_LOCK_INITIALIZER(31){ (0), PTHREAD_MUTEX_STRICT_NP, ((void *)0), 0, -1 }
205};
206
207static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES32] = {
208 &malloc_lock[0],
209 &malloc_lock[1],
210 &malloc_lock[2],
211 &malloc_lock[3],
212 &malloc_lock[4],
213 &malloc_lock[5],
214 &malloc_lock[6],
215 &malloc_lock[7],
216 &malloc_lock[8],
217 &malloc_lock[9],
218 &malloc_lock[10],
219 &malloc_lock[11],
220 &malloc_lock[12],
221 &malloc_lock[13],
222 &malloc_lock[14],
223 &malloc_lock[15],
224 &malloc_lock[16],
225 &malloc_lock[17],
226 &malloc_lock[18],
227 &malloc_lock[19],
228 &malloc_lock[20],
229 &malloc_lock[21],
230 &malloc_lock[22],
231 &malloc_lock[23],
232 &malloc_lock[24],
233 &malloc_lock[25],
234 &malloc_lock[26],
235 &malloc_lock[27],
236 &malloc_lock[28],
237 &malloc_lock[29],
238 &malloc_lock[30],
239 &malloc_lock[31]
240};
241
242void
243_thread_malloc_lock(int i)
244{
245 pthread_mutex_lock(&malloc_mutex[i]);
246}
247
248void
249_thread_malloc_unlock(int i)
250{
251 pthread_mutex_unlock(&malloc_mutex[i]);
252}
253
254static void
255_thread_malloc_reinit(void)
256{
257 int i;
258
259 for (i = 0; i < _MALLOC_MUTEXES32; i++) {
260 malloc_lock[i].lock = _SPINLOCK_UNLOCKED(0);
261#ifndef FUTEX1
262 TAILQ_INIT(&malloc_lock[i].lockers)do { (&malloc_lock[i].lockers)->tqh_first = ((void *)0
); (&malloc_lock[i].lockers)->tqh_last = &(&malloc_lock
[i].lockers)->tqh_first; } while (0)
;
263#endif
264 malloc_lock[i].owner = NULL((void *)0);
265 malloc_lock[i].count = 0;
266 }
267}
268
269/*
270 * atexit lock
271 */
272static _atomic_lock_t atexit_lock = _SPINLOCK_UNLOCKED(0);
273
274void
275_thread_atexit_lock(void)
276{
277 _spinlock(&atexit_lock);
278}
279
280void
281_thread_atexit_unlock(void)
282{
283 _spinunlock(&atexit_lock);
284}
285
286/*
287 * atfork lock
288 */
289static _atomic_lock_t atfork_lock = _SPINLOCK_UNLOCKED(0);
290
291void
292_thread_atfork_lock(void)
293{
294 _spinlock(&atfork_lock);
295}
296
297void
298_thread_atfork_unlock(void)
299{
300 _spinunlock(&atfork_lock);
301}
302
303/*
304 * arc4random lock
305 */
306static _atomic_lock_t arc4_lock = _SPINLOCK_UNLOCKED(0);
307
308void
309_thread_arc4_lock(void)
310{
311 _spinlock(&arc4_lock);
312}
313
314void
315_thread_arc4_unlock(void)
316{
317 _spinunlock(&arc4_lock);
318}
319
320pid_t
321_thread_dofork(pid_t (*sys_fork)(void))
322{
323 int i;
324 pid_t newid;
325
326 _thread_atexit_lock();
327 for (i = 0; i < _MALLOC_MUTEXES32; i++)
328 _thread_malloc_lock(i);
329 _thread_arc4_lock();
330
331 newid = sys_fork();
332
333 _thread_arc4_unlock();
334 if (newid == 0)
335 _thread_malloc_reinit();
336 else
337 for (i = 0; i < _MALLOC_MUTEXES32; i++)
338 _thread_malloc_unlock(i);
339 _thread_atexit_unlock();
340
341 return newid;
342}
343