| File: | 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_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_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_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_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_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"))); |