1 //===-- Tests for pthread_create ------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "src/pthread/pthread_attr_destroy.h" 10 #include "src/pthread/pthread_attr_getdetachstate.h" 11 #include "src/pthread/pthread_attr_getguardsize.h" 12 #include "src/pthread/pthread_attr_getstack.h" 13 #include "src/pthread/pthread_attr_getstacksize.h" 14 #include "src/pthread/pthread_attr_init.h" 15 #include "src/pthread/pthread_attr_setdetachstate.h" 16 #include "src/pthread/pthread_attr_setguardsize.h" 17 #include "src/pthread/pthread_attr_setstack.h" 18 #include "src/pthread/pthread_attr_setstacksize.h" 19 #include "src/pthread/pthread_create.h" 20 #include "src/pthread/pthread_join.h" 21 #include "src/pthread/pthread_self.h" 22 23 #include "src/sys/mman/mmap.h" 24 #include "src/sys/mman/munmap.h" 25 #include "src/sys/random/getrandom.h" 26 27 #include "src/__support/CPP/array.h" 28 #include "src/__support/CPP/atomic.h" 29 #include "src/__support/CPP/new.h" 30 #include "src/__support/threads/thread.h" 31 32 #include "src/errno/libc_errno.h" 33 34 #include "test/IntegrationTest/test.h" 35 36 #include <linux/param.h> // For EXEC_PAGESIZE. 37 #include <pthread.h> 38 39 struct TestThreadArgs { 40 pthread_attr_t attrs; 41 void *ret; 42 }; 43 static __llvm_libc::AllocChecker global_ac; 44 static __llvm_libc::cpp::Atomic<long> global_thr_count = 0; 45 46 static void *successThread(void *Arg) { 47 pthread_t th = __llvm_libc::pthread_self(); 48 auto *thread = reinterpret_cast<__llvm_libc::Thread *>(&th); 49 50 ASSERT_EQ(libc_errno, 0); 51 ASSERT_TRUE(thread); 52 ASSERT_TRUE(thread->attrib); 53 54 TestThreadArgs *th_arg = reinterpret_cast<TestThreadArgs *>(Arg); 55 pthread_attr_t *expec_attrs = &(th_arg->attrs); 56 void *ret = th_arg->ret; 57 58 void *expec_stack; 59 size_t expec_stacksize, expec_guardsize, expec_stacksize2; 60 int expec_detached; 61 62 ASSERT_EQ(__llvm_libc::pthread_attr_getstack(expec_attrs, &expec_stack, 63 &expec_stacksize), 64 0); 65 ASSERT_EQ(libc_errno, 0); 66 67 ASSERT_EQ( 68 __llvm_libc::pthread_attr_getstacksize(expec_attrs, &expec_stacksize2), 69 0); 70 ASSERT_EQ(libc_errno, 0); 71 72 ASSERT_EQ( 73 __llvm_libc::pthread_attr_getguardsize(expec_attrs, &expec_guardsize), 0); 74 ASSERT_EQ(libc_errno, 0); 75 76 ASSERT_EQ( 77 __llvm_libc::pthread_attr_getdetachstate(expec_attrs, &expec_detached), 78 0); 79 ASSERT_EQ(libc_errno, 0); 80 81 ASSERT_EQ(expec_stacksize, expec_stacksize2); 82 83 ASSERT_TRUE(thread->attrib->stack); 84 if (expec_stack != nullptr) { 85 ASSERT_EQ(thread->attrib->stack, expec_stack); 86 } else { 87 ASSERT_EQ(reinterpret_cast<uintptr_t>(thread->attrib->stack) % 88 EXEC_PAGESIZE, 89 static_cast<uintptr_t>(0)); 90 expec_stacksize = (expec_stacksize + EXEC_PAGESIZE - 1) & (-EXEC_PAGESIZE); 91 } 92 93 ASSERT_TRUE(expec_stacksize); 94 ASSERT_EQ(thread->attrib->stacksize, expec_stacksize); 95 ASSERT_EQ(thread->attrib->guardsize, expec_guardsize); 96 97 ASSERT_EQ(expec_detached == PTHREAD_CREATE_JOINABLE, 98 thread->attrib->detach_state.load() == 99 static_cast<uint32_t>(__llvm_libc::DetachState::JOINABLE)); 100 ASSERT_EQ(expec_detached == PTHREAD_CREATE_DETACHED, 101 thread->attrib->detach_state.load() == 102 static_cast<uint32_t>(__llvm_libc::DetachState::DETACHED)); 103 104 { 105 // Allocate some bytes on the stack on most of the stack and make sure we 106 // have read/write permissions on the memory. -EXEC_PAGESIZE / 2 just as a 107 // buffer so we don't go beyond our limits (no nested function calls / not 108 // much other data on the stack so should be enough). 109 size_t test_stacksize = expec_stacksize - EXEC_PAGESIZE / 2; 110 volatile uint8_t *bytes_on_stack = 111 (volatile uint8_t *)__builtin_alloca(test_stacksize); 112 113 for (size_t I = 0; I < test_stacksize; ++I) { 114 // Write permissions 115 bytes_on_stack[I] = static_cast<uint8_t>(I); 116 } 117 118 for (size_t I = 0; I < test_stacksize; ++I) { 119 // Read/write permissions 120 bytes_on_stack[I] += static_cast<uint8_t>(I); 121 } 122 } 123 124 // TODO: If guardsize != 0 && expec_stack == nullptr we should confirm that 125 // [stack - expec_guardsize, stack) is both mapped and has PROT_NONE 126 // permissions. Maybe we can read from /proc/{self}/map? 127 128 ASSERT_EQ(__llvm_libc::pthread_attr_destroy(expec_attrs), 0); 129 ASSERT_EQ(libc_errno, 0); 130 131 // Arg is malloced, so free. 132 delete th_arg; 133 global_thr_count.fetch_sub(1); 134 return ret; 135 } 136 137 static void run_success_config(int detachstate, size_t guardsize, 138 size_t stacksize, bool customstack) { 139 140 TestThreadArgs *th_arg = new (global_ac) TestThreadArgs{}; 141 pthread_attr_t *attr = &(th_arg->attrs); 142 143 ASSERT_EQ(__llvm_libc::pthread_attr_init(attr), 0); 144 ASSERT_EQ(libc_errno, 0); 145 146 ASSERT_EQ(__llvm_libc::pthread_attr_setdetachstate(attr, detachstate), 0); 147 ASSERT_EQ(libc_errno, 0); 148 149 ASSERT_EQ(__llvm_libc::pthread_attr_setguardsize(attr, guardsize), 0); 150 ASSERT_EQ(libc_errno, 0); 151 152 void *Stack = nullptr; 153 if (customstack) { 154 Stack = __llvm_libc::mmap(nullptr, stacksize, PROT_READ | PROT_WRITE, 155 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 156 ASSERT_NE(Stack, MAP_FAILED); 157 ASSERT_NE(Stack, static_cast<void *>(nullptr)); 158 ASSERT_EQ(libc_errno, 0); 159 160 ASSERT_EQ(__llvm_libc::pthread_attr_setstack(attr, Stack, stacksize), 0); 161 ASSERT_EQ(libc_errno, 0); 162 } else { 163 ASSERT_EQ(__llvm_libc::pthread_attr_setstacksize(attr, stacksize), 0); 164 ASSERT_EQ(libc_errno, 0); 165 } 166 167 void *expec_ret = nullptr; 168 if (detachstate == PTHREAD_CREATE_JOINABLE) { 169 ASSERT_EQ(__llvm_libc::getrandom(&expec_ret, sizeof(expec_ret), 0), 170 static_cast<ssize_t>(sizeof(expec_ret))); 171 ASSERT_EQ(libc_errno, 0); 172 } 173 174 th_arg->ret = expec_ret; 175 global_thr_count.fetch_add(1); 176 177 pthread_t tid; 178 // th_arg and attr are cleanup by the thread. 179 ASSERT_EQ(__llvm_libc::pthread_create(&tid, attr, successThread, 180 reinterpret_cast<void *>(th_arg)), 181 0); 182 ASSERT_EQ(libc_errno, 0); 183 184 if (detachstate == PTHREAD_CREATE_JOINABLE) { 185 void *th_ret; 186 ASSERT_EQ(__llvm_libc::pthread_join(tid, &th_ret), 0); 187 ASSERT_EQ(libc_errno, 0); 188 ASSERT_EQ(th_ret, expec_ret); 189 190 if (customstack) { 191 ASSERT_EQ(__llvm_libc::munmap(Stack, stacksize), 0); 192 ASSERT_EQ(libc_errno, 0); 193 } 194 } else { 195 ASSERT_FALSE(customstack); 196 } 197 } 198 199 static void run_success_tests() { 200 201 // Test parameters 202 using __llvm_libc::cpp::array; 203 204 array<int, 2> detachstates = {PTHREAD_CREATE_DETACHED, 205 PTHREAD_CREATE_JOINABLE}; 206 array<size_t, 4> guardsizes = {0, EXEC_PAGESIZE, 2 * EXEC_PAGESIZE, 207 123 * EXEC_PAGESIZE}; 208 array<size_t, 6> stacksizes = {PTHREAD_STACK_MIN, 209 PTHREAD_STACK_MIN + 16, 210 (1 << 16) - EXEC_PAGESIZE / 2, 211 (1 << 16) + EXEC_PAGESIZE / 2, 212 1234560, 213 1234560 * 2}; 214 array<bool, 2> customstacks = {true, false}; 215 216 for (int detachstate : detachstates) { 217 for (size_t guardsize : guardsizes) { 218 for (size_t stacksize : stacksizes) { 219 for (bool customstack : customstacks) { 220 if (customstack) { 221 222 // TODO: figure out how to test a user allocated stack 223 // along with detached pthread safely. We can't let the 224 // thread deallocate it owns stack for obvious 225 // reasons. And there doesn't appear to be a good way to 226 // check if a detached thread has exited. NB: It's racey to just 227 // wait for an atomic variable at the end of the thread function as 228 // internal thread cleanup functions continue to use its stack. 229 // Maybe an `atexit` handler would work. 230 if (detachstate == PTHREAD_CREATE_DETACHED) 231 continue; 232 233 // Guardsize has no meaning with user provided stack. 234 if (guardsize) 235 continue; 236 237 run_success_config(detachstate, guardsize, stacksize, customstack); 238 } 239 } 240 } 241 } 242 } 243 244 // Wait for detached threads to finish testing (this is not gurantee they will 245 // have cleaned up) 246 while (global_thr_count.load()) 247 ; 248 } 249 250 static void *failure_thread(void *) { 251 // Should be unreachable; 252 ASSERT_TRUE(false); 253 return nullptr; 254 } 255 256 static void create_and_check_failure_thread(pthread_attr_t *attr) { 257 pthread_t tid; 258 int result = __llvm_libc::pthread_create(&tid, attr, failure_thread, nullptr); 259 // EINVAL if we caught on overflow or something of that nature. EAGAIN if it 260 // was just really larger we failed mmap. 261 ASSERT_TRUE(result == EINVAL || result == EAGAIN); 262 // pthread_create should NOT set errno on error 263 ASSERT_EQ(libc_errno, 0); 264 265 ASSERT_EQ(__llvm_libc::pthread_attr_destroy(attr), 0); 266 ASSERT_EQ(libc_errno, 0); 267 } 268 269 static void run_failure_config(size_t guardsize, size_t stacksize) { 270 pthread_attr_t attr; 271 guardsize &= -EXEC_PAGESIZE; 272 ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); 273 ASSERT_EQ(libc_errno, 0); 274 275 ASSERT_EQ(__llvm_libc::pthread_attr_setguardsize(&attr, guardsize), 0); 276 ASSERT_EQ(libc_errno, 0); 277 278 ASSERT_EQ(__llvm_libc::pthread_attr_setstacksize(&attr, stacksize), 0); 279 ASSERT_EQ(libc_errno, 0); 280 281 create_and_check_failure_thread(&attr); 282 } 283 284 static void run_failure_tests() { 285 // Just some tests where the user sets "valid" parameters but they fail 286 // (overflow or too large to allocate). 287 run_failure_config(SIZE_MAX, PTHREAD_STACK_MIN); 288 run_failure_config(SIZE_MAX - PTHREAD_STACK_MIN, PTHREAD_STACK_MIN * 2); 289 run_failure_config(PTHREAD_STACK_MIN, SIZE_MAX); 290 run_failure_config(PTHREAD_STACK_MIN, SIZE_MAX - PTHREAD_STACK_MIN); 291 run_failure_config(SIZE_MAX / 2, SIZE_MAX / 2); 292 run_failure_config(SIZE_MAX / 4, SIZE_MAX / 4); 293 run_failure_config(SIZE_MAX / 2 + 1234, SIZE_MAX / 2); 294 295 // Test invalid parameters that are impossible to obtain via the 296 // `pthread_attr_set*` API. Still test that this not entirely unlikely 297 // initialization doesn't cause any issues. Basically we wan't to make sure 298 // that `pthread_create` properly checks for input validity and doesn't rely 299 // on the `pthread_attr_set*` API. 300 pthread_attr_t attr; 301 302 // Stacksize too small. 303 ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); 304 ASSERT_EQ(libc_errno, 0); 305 attr.__stacksize = PTHREAD_STACK_MIN - 16; 306 create_and_check_failure_thread(&attr); 307 308 // Stack misaligned. 309 ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); 310 ASSERT_EQ(libc_errno, 0); 311 attr.__stack = reinterpret_cast<void *>(1); 312 create_and_check_failure_thread(&attr); 313 314 // Stack + stacksize misaligned. 315 ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); 316 ASSERT_EQ(libc_errno, 0); 317 attr.__stacksize = PTHREAD_STACK_MIN + 1; 318 attr.__stack = reinterpret_cast<void *>(16); 319 create_and_check_failure_thread(&attr); 320 321 // Guardsize misaligned. 322 ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); 323 ASSERT_EQ(libc_errno, 0); 324 attr.__guardsize = EXEC_PAGESIZE / 2; 325 create_and_check_failure_thread(&attr); 326 327 // Detachstate is unknown. 328 ASSERT_EQ(__llvm_libc::pthread_attr_init(&attr), 0); 329 ASSERT_EQ(libc_errno, 0); 330 attr.__detachstate = -1; 331 create_and_check_failure_thread(&attr); 332 } 333 334 TEST_MAIN() { 335 libc_errno = 0; 336 run_success_tests(); 337 run_failure_tests(); 338 return 0; 339 } 340