File: | src/thread/pthread_create.c |
Location: | line 232, column 7 |
Description: | Branch condition evaluates to a garbage value |
1 | #define _GNU_SOURCE | |||
2 | #include "pthread_impl.h" | |||
3 | #include "stdio_impl.h" | |||
4 | #include "libc.h" | |||
5 | #include <sys/mman.h> | |||
6 | #include <string.h> | |||
7 | #include <stddef.h> | |||
8 | ||||
9 | void *__mmap(void *, size_t, int, int, int, off_t); | |||
10 | int __munmap(void *, size_t); | |||
11 | int __mprotect(void *, size_t, int); | |||
12 | ||||
13 | static void dummy_0() | |||
14 | { | |||
15 | } | |||
16 | weak_alias(dummy_0, __acquire_ptc)extern __typeof(dummy_0) __acquire_ptc __attribute__((weak, alias ("dummy_0"))); | |||
17 | weak_alias(dummy_0, __release_ptc)extern __typeof(dummy_0) __release_ptc __attribute__((weak, alias ("dummy_0"))); | |||
18 | weak_alias(dummy_0, __pthread_tsd_run_dtors)extern __typeof(dummy_0) __pthread_tsd_run_dtors __attribute__ ((weak, alias("dummy_0"))); | |||
19 | weak_alias(dummy_0, __do_orphaned_stdio_locks)extern __typeof(dummy_0) __do_orphaned_stdio_locks __attribute__ ((weak, alias("dummy_0"))); | |||
20 | weak_alias(dummy_0, __dl_thread_cleanup)extern __typeof(dummy_0) __dl_thread_cleanup __attribute__((weak , alias("dummy_0"))); | |||
21 | ||||
22 | _Noreturn__attribute__((__noreturn__)) void __pthread_exit(void *result) | |||
23 | { | |||
24 | pthread_t self = __pthread_self(); | |||
25 | sigset_t set; | |||
26 | ||||
27 | self->canceldisable = 1; | |||
28 | self->cancelasync = 0; | |||
29 | self->result = result; | |||
30 | ||||
31 | while (self->cancelbuf) { | |||
32 | void (*f)(void *) = self->cancelbuf->__f; | |||
33 | void *x = self->cancelbuf->__x; | |||
34 | self->cancelbuf = self->cancelbuf->__next; | |||
35 | f(x); | |||
36 | } | |||
37 | ||||
38 | __pthread_tsd_run_dtors(); | |||
39 | ||||
40 | __lock(self->exitlock); | |||
41 | ||||
42 | /* Mark this thread dead before decrementing count */ | |||
43 | __lock(self->killlock); | |||
44 | self->dead = 1; | |||
45 | ||||
46 | /* Block all signals before decrementing the live thread count. | |||
47 | * This is important to ensure that dynamically allocated TLS | |||
48 | * is not under-allocated/over-committed, and possibly for other | |||
49 | * reasons as well. */ | |||
50 | __block_all_sigs(&set); | |||
51 | ||||
52 | /* Wait to unlock the kill lock, which governs functions like | |||
53 | * pthread_kill which target a thread id, until signals have | |||
54 | * been blocked. This precludes observation of the thread id | |||
55 | * as a live thread (with application code running in it) after | |||
56 | * the thread was reported dead by ESRCH being returned. */ | |||
57 | __unlock(self->killlock); | |||
58 | ||||
59 | /* It's impossible to determine whether this is "the last thread" | |||
60 | * until performing the atomic decrement, since multiple threads | |||
61 | * could exit at the same time. For the last thread, revert the | |||
62 | * decrement and unblock signals to give the atexit handlers and | |||
63 | * stdio cleanup code a consistent state. */ | |||
64 | if (a_fetch_adda_fetch_add(&libc__libc.threads_minus_1, -1)==0) { | |||
65 | libc__libc.threads_minus_1 = 0; | |||
66 | __restore_sigs(&set); | |||
67 | exit(0); | |||
68 | } | |||
69 | ||||
70 | /* Process robust list in userspace to handle non-pshared mutexes | |||
71 | * and the detached thread case where the robust list head will | |||
72 | * be invalid when the kernel would process it. */ | |||
73 | __vm_lock(); | |||
74 | volatile void *volatile *rp; | |||
75 | while ((rp=self->robust_list.head) && rp != &self->robust_list.head) { | |||
76 | pthread_mutex_t *m = (void *)((char *)rp | |||
77 | - offsetof(pthread_mutex_t, _m_next)__builtin_offsetof(pthread_mutex_t, __u.__p[4])); | |||
78 | int waiters = m->_m_waiters__u.__vi[2]; | |||
79 | int priv = (m->_m_type__u.__i[0] & 128) ^ 128; | |||
80 | self->robust_list.pending = rp; | |||
81 | self->robust_list.head = *rp; | |||
82 | int cont = a_swapa_swap(&m->_m_lock__u.__vi[1], self->tid|0x40000000); | |||
83 | self->robust_list.pending = 0; | |||
84 | if (cont < 0 || waiters) | |||
85 | __wake(&m->_m_lock__u.__vi[1], 1, priv); | |||
86 | } | |||
87 | __vm_unlock(); | |||
88 | ||||
89 | __do_orphaned_stdio_locks(); | |||
90 | __dl_thread_cleanup(); | |||
91 | ||||
92 | if (self->detached && self->map_base) { | |||
93 | /* Detached threads must avoid the kernel clear_child_tid | |||
94 | * feature, since the virtual address will have been | |||
95 | * unmapped and possibly already reused by a new mapping | |||
96 | * at the time the kernel would perform the write. In | |||
97 | * the case of threads that started out detached, the | |||
98 | * initial clone flags are correct, but if the thread was | |||
99 | * detached later (== 2), we need to clear it here. */ | |||
100 | if (self->detached == 2) __syscall(SYS_set_tid_address, 0)__syscall1(218,((long) (0))); | |||
101 | ||||
102 | /* Robust list will no longer be valid, and was already | |||
103 | * processed above, so unregister it with the kernel. */ | |||
104 | if (self->robust_list.off) | |||
105 | __syscall(SYS_set_robust_list, 0, 3*sizeof(long))__syscall2(273,((long) (0)),((long) (3*sizeof(long)))); | |||
106 | ||||
107 | /* Since __unmapself bypasses the normal munmap code path, | |||
108 | * explicitly wait for vmlock holders first. */ | |||
109 | __vm_wait(); | |||
110 | ||||
111 | /* The following call unmaps the thread's stack mapping | |||
112 | * and then exits without touching the stack. */ | |||
113 | __unmapself(self->map_base, self->map_size); | |||
114 | } | |||
115 | ||||
116 | for (;;) __syscall(SYS_exit, 0)__syscall1(60,((long) (0))); | |||
117 | } | |||
118 | ||||
119 | void __do_cleanup_push(struct __ptcb *cb) | |||
120 | { | |||
121 | struct pthread__pthread *self = __pthread_self(); | |||
122 | cb->__next = self->cancelbuf; | |||
123 | self->cancelbuf = cb; | |||
124 | } | |||
125 | ||||
126 | void __do_cleanup_pop(struct __ptcb *cb) | |||
127 | { | |||
128 | __pthread_self()->cancelbuf = cb->__next; | |||
129 | } | |||
130 | ||||
131 | static int start(void *p) | |||
132 | { | |||
133 | pthread_t self = p; | |||
134 | if (self->startlock[0]) { | |||
135 | __wait(self->startlock, 0, 1, 1); | |||
136 | if (self->startlock[0]) { | |||
137 | self->detached = 2; | |||
138 | pthread_exit(0); | |||
139 | } | |||
140 | __restore_sigs(self->sigmask); | |||
141 | } | |||
142 | if (self->unblock_cancel) | |||
143 | __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,__syscall4(14,((long) (1)),((long) (((sigset_t *)(const unsigned long [65/8/sizeof(long)]){ [sizeof(long)==4] = 3UL<<(32 *(sizeof(long)>4)) }))),((long) (0)),((long) (65/8))) | |||
144 | SIGPT_SET, 0, _NSIG/8)__syscall4(14,((long) (1)),((long) (((sigset_t *)(const unsigned long [65/8/sizeof(long)]){ [sizeof(long)==4] = 3UL<<(32 *(sizeof(long)>4)) }))),((long) (0)),((long) (65/8))); | |||
145 | __pthread_exit(self->start(self->start_arg)); | |||
146 | return 0; | |||
147 | } | |||
148 | ||||
149 | static int start_c11(void *p) | |||
150 | { | |||
151 | pthread_t self = p; | |||
152 | int (*start)(void*) = (int(*)(void*)) self->start; | |||
153 | __pthread_exit((void *)(uintptr_t)start(self->start_arg)); | |||
154 | return 0; | |||
155 | } | |||
156 | ||||
157 | #define ROUND(x)(((x)+4096 -1)&-4096) (((x)+PAGE_SIZE4096-1)&-PAGE_SIZE4096) | |||
158 | ||||
159 | /* pthread_key_create.c overrides this */ | |||
160 | static volatile size_t dummy = 0; | |||
161 | weak_alias(dummy, __pthread_tsd_size)extern __typeof(dummy) __pthread_tsd_size __attribute__((weak , alias("dummy"))); | |||
162 | static void *dummy_tsd[1] = { 0 }; | |||
163 | weak_alias(dummy_tsd, __pthread_tsd_main)extern __typeof(dummy_tsd) __pthread_tsd_main __attribute__(( weak, alias("dummy_tsd"))); | |||
164 | ||||
165 | volatile int __block_new_threads = 0; | |||
166 | ||||
167 | static FILE *volatile dummy_file = 0; | |||
168 | weak_alias(dummy_file, __stdin_used)extern __typeof(dummy_file) __stdin_used __attribute__((weak, alias("dummy_file"))); | |||
169 | weak_alias(dummy_file, __stdout_used)extern __typeof(dummy_file) __stdout_used __attribute__((weak , alias("dummy_file"))); | |||
170 | weak_alias(dummy_file, __stderr_used)extern __typeof(dummy_file) __stderr_used __attribute__((weak , alias("dummy_file"))); | |||
171 | ||||
172 | static void init_file_lock(FILE *f) | |||
173 | { | |||
174 | if (f && f->lock<0) f->lock = 0; | |||
175 | } | |||
176 | ||||
177 | void *__copy_tls(unsigned char *); | |||
178 | ||||
179 | int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) | |||
180 | { | |||
181 | int ret, c11 = (attrp == __ATTRP_C11_THREAD((void*)(uintptr_t)-1)); | |||
182 | size_t size, guard; | |||
| ||||
183 | struct pthread__pthread *self, *new; | |||
184 | unsigned char *map = 0, *stack = 0, *tsd = 0, *stack_limit; | |||
185 | unsigned flags = CLONE_VM0x00000100 | CLONE_FS0x00000200 | CLONE_FILES0x00000400 | CLONE_SIGHAND0x00000800 | |||
186 | | CLONE_THREAD0x00010000 | CLONE_SYSVSEM0x00040000 | CLONE_SETTLS0x00080000 | |||
187 | | CLONE_PARENT_SETTID0x00100000 | CLONE_CHILD_CLEARTID0x00200000 | CLONE_DETACHED0x00400000; | |||
188 | int do_sched = 0; | |||
189 | pthread_attr_t attr = {0}; | |||
190 | ||||
191 | if (!libc__libc.can_do_threads) return ENOSYS38; | |||
192 | self = __pthread_self(); | |||
193 | if (!libc__libc.threaded) { | |||
194 | for (FILE *f=*__ofl_lock(); f; f=f->next) | |||
195 | init_file_lock(f); | |||
196 | __ofl_unlock(); | |||
197 | init_file_lock(__stdin_used); | |||
198 | init_file_lock(__stdout_used); | |||
199 | init_file_lock(__stderr_used); | |||
200 | __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8)__syscall4(14,((long) (1)),((long) (((sigset_t *)(const unsigned long [65/8/sizeof(long)]){ [sizeof(long)==4] = 3UL<<(32 *(sizeof(long)>4)) }))),((long) (0)),((long) (65/8))); | |||
201 | self->tsd = (void **)__pthread_tsd_main; | |||
202 | libc__libc.threaded = 1; | |||
203 | } | |||
204 | if (attrp && !c11) attr = *attrp; | |||
205 | ||||
206 | __acquire_ptc(); | |||
207 | if (__block_new_threads) __wait(&__block_new_threads, 0, 1, 1); | |||
208 | ||||
209 | if (attr._a_stackaddr__u.__s[2]) { | |||
210 | size_t need = libc__libc.tls_size + __pthread_tsd_size; | |||
211 | size = attr._a_stacksize__u.__s[0] + DEFAULT_STACK_SIZE81920; | |||
212 | stack = (void *)(attr._a_stackaddr__u.__s[2] & -16); | |||
213 | stack_limit = (void *)(attr._a_stackaddr__u.__s[2] - size); | |||
214 | /* Use application-provided stack for TLS only when | |||
215 | * it does not take more than ~12% or 2k of the | |||
216 | * application's stack space. */ | |||
217 | if (need < size/8 && need < 2048) { | |||
218 | tsd = stack - __pthread_tsd_size; | |||
219 | stack = tsd - libc__libc.tls_size; | |||
220 | memset(stack, 0, need); | |||
221 | } else { | |||
222 | size = ROUND(need)(((need)+4096 -1)&-4096); | |||
223 | guard = 0; | |||
224 | } | |||
225 | } else { | |||
226 | guard = ROUND(DEFAULT_GUARD_SIZE + attr._a_guardsize)(((4096 + attr.__u.__s[1])+4096 -1)&-4096); | |||
227 | size = guard + ROUND(DEFAULT_STACK_SIZE + attr._a_stacksize(((81920 + attr.__u.__s[0] + __libc.tls_size + __pthread_tsd_size )+4096 -1)&-4096) | |||
228 | + libc.tls_size + __pthread_tsd_size)(((81920 + attr.__u.__s[0] + __libc.tls_size + __pthread_tsd_size )+4096 -1)&-4096); | |||
229 | } | |||
230 | ||||
231 | if (!tsd) { | |||
232 | if (guard) { | |||
| ||||
233 | map = __mmap(0, size, PROT_NONE0, MAP_PRIVATE0x02|MAP_ANON0x20, -1, 0); | |||
234 | if (map == MAP_FAILED((void *) -1)) goto fail; | |||
235 | if (__mprotect(map+guard, size-guard, PROT_READ1|PROT_WRITE2) | |||
236 | && errno(*__errno_location()) != ENOSYS38) { | |||
237 | __munmap(map, size); | |||
238 | goto fail; | |||
239 | } | |||
240 | } else { | |||
241 | map = __mmap(0, size, PROT_READ1|PROT_WRITE2, MAP_PRIVATE0x02|MAP_ANON0x20, -1, 0); | |||
242 | if (map == MAP_FAILED((void *) -1)) goto fail; | |||
243 | } | |||
244 | tsd = map + size - __pthread_tsd_size; | |||
245 | if (!stack) { | |||
246 | stack = tsd - libc__libc.tls_size; | |||
247 | stack_limit = map + guard; | |||
248 | } | |||
249 | } | |||
250 | ||||
251 | new = __copy_tls(tsd - libc__libc.tls_size); | |||
252 | new->map_base = map; | |||
253 | new->map_size = size; | |||
254 | new->stack = stack; | |||
255 | new->stack_size = stack - stack_limit; | |||
256 | new->start = entry; | |||
257 | new->start_arg = arg; | |||
258 | new->self = new; | |||
259 | new->tsd = (void *)tsd; | |||
260 | new->locale = &libc__libc.global_locale; | |||
261 | if (attr._a_detach__u.__i[3*(sizeof(size_t)/sizeof(int))+0]) { | |||
262 | new->detached = 1; | |||
263 | flags -= CLONE_CHILD_CLEARTID0x00200000; | |||
264 | } | |||
265 | if (attr._a_sched__u.__i[3*(sizeof(size_t)/sizeof(int))+1]) { | |||
266 | do_sched = new->startlock[0] = 1; | |||
267 | __block_app_sigs(new->sigmask); | |||
268 | } | |||
269 | new->robust_list.head = &new->robust_list.head; | |||
270 | new->unblock_cancel = self->cancel; | |||
271 | new->CANARYcanary = self->CANARYcanary; | |||
272 | ||||
273 | a_inca_inc(&libc__libc.threads_minus_1); | |||
274 | ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new)(new), &new->tid); | |||
275 | ||||
276 | __release_ptc(); | |||
277 | ||||
278 | if (do_sched) { | |||
279 | __restore_sigs(new->sigmask); | |||
280 | } | |||
281 | ||||
282 | if (ret < 0) { | |||
283 | a_deca_dec(&libc__libc.threads_minus_1); | |||
284 | if (map) __munmap(map, size); | |||
285 | return EAGAIN11; | |||
286 | } | |||
287 | ||||
288 | if (do_sched) { | |||
289 | ret = __syscall(SYS_sched_setscheduler, new->tid,__syscall3(144,((long) (new->tid)),((long) (attr.__u.__i[3 *(sizeof(size_t)/sizeof(int))+2])),((long) (&attr.__u.__i [3*(sizeof(size_t)/sizeof(int))+3]))) | |||
290 | attr._a_policy, &attr._a_prio)__syscall3(144,((long) (new->tid)),((long) (attr.__u.__i[3 *(sizeof(size_t)/sizeof(int))+2])),((long) (&attr.__u.__i [3*(sizeof(size_t)/sizeof(int))+3]))); | |||
291 | a_storea_store(new->startlock, ret<0 ? 2 : 0); | |||
292 | __wake(new->startlock, 1, 1); | |||
293 | if (ret < 0) return -ret; | |||
294 | } | |||
295 | ||||
296 | *res = new; | |||
297 | return 0; | |||
298 | fail: | |||
299 | __release_ptc(); | |||
300 | return EAGAIN11; | |||
301 | } | |||
302 | ||||
303 | weak_alias(__pthread_exit, pthread_exit)extern __typeof(__pthread_exit) pthread_exit __attribute__((weak , alias("__pthread_exit"))); | |||
304 | weak_alias(__pthread_create, pthread_create)extern __typeof(__pthread_create) pthread_create __attribute__ ((weak, alias("__pthread_create"))); |