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
39struct TestThreadArgs {
40 pthread_attr_t attrs;
41 void *ret;
42};
43static LIBC_NAMESPACE::AllocChecker global_ac;
44static LIBC_NAMESPACE::cpp::Atomic<long> global_thr_count = 0;
45
46static void *successThread(void *Arg) {
47 pthread_t th = LIBC_NAMESPACE::pthread_self();
48 auto *thread = reinterpret_cast<LIBC_NAMESPACE::Thread *>(&th);
49
50 ASSERT_ERRNO_SUCCESS();
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(LIBC_NAMESPACE::pthread_attr_getstack(expec_attrs, &expec_stack,
63 &expec_stacksize),
64 0);
65 ASSERT_ERRNO_SUCCESS();
66
67 ASSERT_EQ(
68 LIBC_NAMESPACE::pthread_attr_getstacksize(expec_attrs, &expec_stacksize2),
69 0);
70 ASSERT_ERRNO_SUCCESS();
71
72 ASSERT_EQ(
73 LIBC_NAMESPACE::pthread_attr_getguardsize(expec_attrs, &expec_guardsize),
74 0);
75 ASSERT_ERRNO_SUCCESS();
76
77 ASSERT_EQ(
78 LIBC_NAMESPACE::pthread_attr_getdetachstate(expec_attrs, &expec_detached),
79 0);
80 ASSERT_ERRNO_SUCCESS();
81
82 ASSERT_EQ(expec_stacksize, expec_stacksize2);
83
84 ASSERT_TRUE(thread->attrib->stack);
85 if (expec_stack != nullptr) {
86 ASSERT_EQ(thread->attrib->stack, expec_stack);
87 } else {
88 ASSERT_EQ(reinterpret_cast<uintptr_t>(thread->attrib->stack) %
89 EXEC_PAGESIZE,
90 static_cast<uintptr_t>(0));
91 expec_stacksize = (expec_stacksize + EXEC_PAGESIZE - 1) & (-EXEC_PAGESIZE);
92 }
93
94 ASSERT_TRUE(expec_stacksize);
95 ASSERT_EQ(thread->attrib->stacksize, expec_stacksize);
96 ASSERT_EQ(thread->attrib->guardsize, expec_guardsize);
97
98 ASSERT_EQ(expec_detached == PTHREAD_CREATE_JOINABLE,
99 thread->attrib->detach_state.load() ==
100 static_cast<uint32_t>(LIBC_NAMESPACE::DetachState::JOINABLE));
101 ASSERT_EQ(expec_detached == PTHREAD_CREATE_DETACHED,
102 thread->attrib->detach_state.load() ==
103 static_cast<uint32_t>(LIBC_NAMESPACE::DetachState::DETACHED));
104
105 {
106 // Allocate some bytes on the stack on most of the stack and make sure we
107 // have read/write permissions on the memory.
108 size_t test_stacksize = expec_stacksize - 1024;
109 volatile uint8_t *bytes_on_stack =
110 (volatile uint8_t *)__builtin_alloca(test_stacksize);
111
112 for (size_t I = 0; I < test_stacksize; ++I) {
113 // Write permissions
114 bytes_on_stack[I] = static_cast<uint8_t>(I);
115 }
116
117 for (size_t I = 0; I < test_stacksize; ++I) {
118 // Read/write permissions
119 bytes_on_stack[I] += static_cast<uint8_t>(I);
120 }
121 }
122
123 // TODO: If guardsize != 0 && expec_stack == nullptr we should confirm that
124 // [stack - expec_guardsize, stack) is both mapped and has PROT_NONE
125 // permissions. Maybe we can read from /proc/{self}/map?
126
127 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_destroy(expec_attrs), 0);
128 ASSERT_ERRNO_SUCCESS();
129
130 // Arg is malloced, so free.
131 delete th_arg;
132 global_thr_count.fetch_sub(decrement: 1);
133 return ret;
134}
135
136static void run_success_config(int detachstate, size_t guardsize,
137 size_t stacksize, bool customstack) {
138
139 TestThreadArgs *th_arg = new (global_ac) TestThreadArgs{};
140 pthread_attr_t *attr = &(th_arg->attrs);
141
142 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(attr), 0);
143 ASSERT_ERRNO_SUCCESS();
144
145 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setdetachstate(attr, detachstate), 0);
146 ASSERT_ERRNO_SUCCESS();
147
148 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setguardsize(attr, guardsize), 0);
149 ASSERT_ERRNO_SUCCESS();
150
151 void *Stack = nullptr;
152 if (customstack) {
153 Stack = LIBC_NAMESPACE::mmap(addr: nullptr, size: stacksize, PROT_READ | PROT_WRITE,
154 MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0);
155 ASSERT_NE(Stack, MAP_FAILED);
156 ASSERT_NE(Stack, static_cast<void *>(nullptr));
157 ASSERT_ERRNO_SUCCESS();
158
159 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setstack(attr, Stack, stacksize), 0);
160 ASSERT_ERRNO_SUCCESS();
161 } else {
162 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setstacksize(attr, stacksize), 0);
163 ASSERT_ERRNO_SUCCESS();
164 }
165
166 void *expec_ret = nullptr;
167 if (detachstate == PTHREAD_CREATE_JOINABLE) {
168 ASSERT_EQ(LIBC_NAMESPACE::getrandom(&expec_ret, sizeof(expec_ret), 0),
169 static_cast<ssize_t>(sizeof(expec_ret)));
170 ASSERT_ERRNO_SUCCESS();
171 }
172
173 th_arg->ret = expec_ret;
174 global_thr_count.fetch_add(increment: 1);
175
176 pthread_t tid;
177 // th_arg and attr are cleanup by the thread.
178 ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&tid, attr, successThread,
179 reinterpret_cast<void *>(th_arg)),
180 0);
181 ASSERT_ERRNO_SUCCESS();
182
183 if (detachstate == PTHREAD_CREATE_JOINABLE) {
184 void *th_ret;
185 ASSERT_EQ(LIBC_NAMESPACE::pthread_join(tid, &th_ret), 0);
186 ASSERT_ERRNO_SUCCESS();
187 ASSERT_EQ(th_ret, expec_ret);
188
189 if (customstack) {
190 ASSERT_EQ(LIBC_NAMESPACE::munmap(Stack, stacksize), 0);
191 ASSERT_ERRNO_SUCCESS();
192 }
193 } else {
194 ASSERT_FALSE(customstack);
195 }
196}
197
198static void run_success_tests() {
199
200 // Test parameters
201 using LIBC_NAMESPACE::cpp::array;
202
203 array<int, 2> detachstates = {PTHREAD_CREATE_DETACHED,
204 PTHREAD_CREATE_JOINABLE};
205 array<size_t, 4> guardsizes = {0, EXEC_PAGESIZE, 2 * EXEC_PAGESIZE,
206 123 * EXEC_PAGESIZE};
207 array<size_t, 6> stacksizes = {PTHREAD_STACK_MIN,
208 PTHREAD_STACK_MIN + 16,
209 (1 << 16) - EXEC_PAGESIZE / 2,
210 (1 << 16) + EXEC_PAGESIZE / 2,
211 1234560,
212 1234560 * 2};
213 array<bool, 2> customstacks = {true, false};
214
215 for (int detachstate : detachstates) {
216 for (size_t guardsize : guardsizes) {
217 for (size_t stacksize : stacksizes) {
218 for (bool customstack : customstacks) {
219 if (customstack) {
220
221 // TODO: figure out how to test a user allocated stack
222 // along with detached pthread safely. We can't let the
223 // thread deallocate it owns stack for obvious
224 // reasons. And there doesn't appear to be a good way to
225 // check if a detached thread has exited. NB: It's racey to just
226 // wait for an atomic variable at the end of the thread function as
227 // internal thread cleanup functions continue to use its stack.
228 // Maybe an `atexit` handler would work.
229 if (detachstate == PTHREAD_CREATE_DETACHED)
230 continue;
231
232 // Guardsize has no meaning with user provided stack.
233 if (guardsize)
234 continue;
235
236 run_success_config(detachstate, guardsize, stacksize, customstack);
237 }
238 }
239 }
240 }
241 }
242
243 // Wait for detached threads to finish testing (this is not gurantee they will
244 // have cleaned up)
245 while (global_thr_count.load())
246 ;
247}
248
249static void *failure_thread(void *) {
250 // Should be unreachable;
251 ASSERT_TRUE(false);
252 return nullptr;
253}
254
255static void create_and_check_failure_thread(pthread_attr_t *attr) {
256 pthread_t tid;
257 int result =
258 LIBC_NAMESPACE::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_ERRNO_SUCCESS();
264
265 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_destroy(attr), 0);
266 ASSERT_ERRNO_SUCCESS();
267}
268
269static void run_failure_config(size_t guardsize, size_t stacksize) {
270 pthread_attr_t attr;
271 guardsize &= -EXEC_PAGESIZE;
272 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
273 ASSERT_ERRNO_SUCCESS();
274
275 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setguardsize(&attr, guardsize), 0);
276 ASSERT_ERRNO_SUCCESS();
277
278 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setstacksize(&attr, stacksize), 0);
279 ASSERT_ERRNO_SUCCESS();
280
281 create_and_check_failure_thread(attr: &attr);
282}
283
284static 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(guardsize: 3 * (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(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
304 ASSERT_ERRNO_SUCCESS();
305 attr.__stacksize = PTHREAD_STACK_MIN - 16;
306 create_and_check_failure_thread(attr: &attr);
307
308 // Stack misaligned.
309 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
310 ASSERT_ERRNO_SUCCESS();
311 attr.__stack = reinterpret_cast<void *>(1);
312 create_and_check_failure_thread(attr: &attr);
313
314 // Stack + stacksize misaligned.
315 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
316 ASSERT_ERRNO_SUCCESS();
317 attr.__stacksize = PTHREAD_STACK_MIN + 1;
318 attr.__stack = reinterpret_cast<void *>(16);
319 create_and_check_failure_thread(attr: &attr);
320
321 // Guardsize misaligned.
322 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
323 ASSERT_ERRNO_SUCCESS();
324 attr.__guardsize = EXEC_PAGESIZE / 2;
325 create_and_check_failure_thread(attr: &attr);
326
327 // Detachstate is unknown.
328 ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
329 ASSERT_ERRNO_SUCCESS();
330 attr.__detachstate = -1;
331 create_and_check_failure_thread(attr: &attr);
332}
333
334TEST_MAIN() {
335 LIBC_NAMESPACE::libc_errno = 0;
336 run_success_tests();
337 run_failure_tests();
338 return 0;
339}
340

source code of libc/test/integration/src/pthread/pthread_create_test.cpp