1 1.6 riastrad /* $NetBSD: t_stack.c,v 1.6 2023/11/28 02:54:33 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2023 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * Redistribution and use in source and binary forms, with or without 8 1.1 riastrad * modification, are permitted provided that the following conditions 9 1.1 riastrad * are met: 10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 11 1.1 riastrad * notice, this list of conditions and the following disclaimer. 12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 14 1.1 riastrad * documentation and/or other materials provided with the distribution. 15 1.1 riastrad * 16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 27 1.1 riastrad */ 28 1.1 riastrad 29 1.1 riastrad #define _KMEMUSER /* __MACHINE_STACK_GROWS_UP */ 30 1.1 riastrad 31 1.1 riastrad #include <sys/cdefs.h> 32 1.6 riastrad __RCSID("$NetBSD: t_stack.c,v 1.6 2023/11/28 02:54:33 riastradh Exp $"); 33 1.1 riastrad 34 1.1 riastrad #include <sys/mman.h> 35 1.2 riastrad #include <sys/param.h> 36 1.2 riastrad #include <sys/sysctl.h> 37 1.1 riastrad #include <sys/types.h> 38 1.1 riastrad 39 1.2 riastrad #include <uvm/uvm_param.h> /* VM_THREAD_GUARD_SIZE */ 40 1.2 riastrad 41 1.1 riastrad #include <atf-c.h> 42 1.1 riastrad #include <pthread.h> 43 1.1 riastrad #include <setjmp.h> 44 1.1 riastrad #include <signal.h> 45 1.1 riastrad #include <string.h> 46 1.1 riastrad #include <unistd.h> 47 1.1 riastrad 48 1.1 riastrad #include "h_macros.h" 49 1.1 riastrad 50 1.1 riastrad struct jmp_ctx { 51 1.1 riastrad jmp_buf buf; 52 1.1 riastrad }; 53 1.1 riastrad 54 1.1 riastrad /* 55 1.1 riastrad * State used by various tests. 56 1.1 riastrad */ 57 1.1 riastrad struct ctx { 58 1.1 riastrad size_t size; /* default stack size */ 59 1.2 riastrad size_t guardsize; /* default guard size */ 60 1.1 riastrad void *addr; /* user-allocated stack */ 61 1.1 riastrad pthread_key_t jmp_key; /* jmp_ctx to return from SIGSEGV handler */ 62 1.1 riastrad } ctx, *C = &ctx; 63 1.1 riastrad 64 1.1 riastrad /* 65 1.1 riastrad * getdefaultstacksize() 66 1.1 riastrad * 67 1.1 riastrad * Return the default stack size for threads created with 68 1.1 riastrad * pthread_create. 69 1.1 riastrad */ 70 1.1 riastrad static size_t 71 1.1 riastrad getdefaultstacksize(void) 72 1.1 riastrad { 73 1.1 riastrad pthread_attr_t attr; 74 1.1 riastrad size_t stacksize; 75 1.1 riastrad 76 1.1 riastrad /* 77 1.1 riastrad * When called from the main thread, this returns the default 78 1.1 riastrad * stack size (pthread__stacksize) used for pthreads. 79 1.1 riastrad */ 80 1.1 riastrad RZ(pthread_getattr_np(pthread_self(), &attr)); 81 1.1 riastrad RZ(pthread_attr_getstacksize(&attr, &stacksize)); 82 1.1 riastrad RZ(pthread_attr_destroy(&attr)); 83 1.1 riastrad 84 1.1 riastrad /* 85 1.1 riastrad * Verify that the assumption above holds. 86 1.1 riastrad */ 87 1.1 riastrad extern size_t pthread__stacksize; /* pthread_int.h */ 88 1.1 riastrad ATF_CHECK_EQ_MSG(stacksize, pthread__stacksize, 89 1.1 riastrad "stacksize=%zu pthread__stacksize=%zu", 90 1.1 riastrad stacksize, pthread__stacksize); 91 1.1 riastrad 92 1.1 riastrad return stacksize; 93 1.1 riastrad } 94 1.1 riastrad 95 1.1 riastrad /* 96 1.1 riastrad * getnondefaultstacksize() 97 1.1 riastrad * 98 1.1 riastrad * Return a stack size that is not the default stack size for 99 1.1 riastrad * threads created with pthread_create. 100 1.1 riastrad */ 101 1.1 riastrad static size_t 102 1.1 riastrad getnondefaultstacksize(void) 103 1.1 riastrad { 104 1.1 riastrad 105 1.1 riastrad return getdefaultstacksize() + sysconf(_SC_PAGESIZE); 106 1.1 riastrad } 107 1.1 riastrad 108 1.1 riastrad /* 109 1.2 riastrad * getdefaultguardsize() 110 1.2 riastrad * 111 1.2 riastrad * Return the default guard size for threads created with 112 1.2 riastrad * pthread_create. 113 1.2 riastrad */ 114 1.2 riastrad static size_t 115 1.2 riastrad getdefaultguardsize(void) 116 1.2 riastrad { 117 1.2 riastrad const int mib[2] = { CTL_VM, VM_THREAD_GUARD_SIZE }; 118 1.2 riastrad unsigned guardsize; 119 1.2 riastrad size_t len = sizeof(guardsize); 120 1.2 riastrad 121 1.2 riastrad RL(sysctl(mib, __arraycount(mib), &guardsize, &len, NULL, 0)); 122 1.2 riastrad ATF_REQUIRE_EQ_MSG(len, sizeof(guardsize), 123 1.2 riastrad "len=%zu sizeof(guardsize)=%zu", len, sizeof(guardsize)); 124 1.2 riastrad 125 1.2 riastrad /* 126 1.2 riastrad * Verify this matches what libpthread determined. 127 1.2 riastrad */ 128 1.2 riastrad extern size_t pthread__guardsize; /* pthread_int.h */ 129 1.2 riastrad ATF_CHECK_EQ_MSG(guardsize, pthread__guardsize, 130 1.5 riastrad "guardsize=%u pthread__guardsize=%zu", 131 1.2 riastrad guardsize, pthread__guardsize); 132 1.2 riastrad 133 1.2 riastrad return guardsize; 134 1.2 riastrad } 135 1.2 riastrad 136 1.2 riastrad /* 137 1.1 riastrad * alloc(nbytes) 138 1.1 riastrad * 139 1.1 riastrad * Allocate an nbytes-long page-aligned read/write region and 140 1.1 riastrad * return a pointer to it. Abort the test if allocation fails, so 141 1.1 riastrad * if this function returns it succeeds. 142 1.1 riastrad */ 143 1.1 riastrad static void * 144 1.1 riastrad alloc(size_t nbytes) 145 1.1 riastrad { 146 1.1 riastrad void *ptr; 147 1.1 riastrad 148 1.1 riastrad REQUIRE_LIBC((ptr = mmap(/*hint*/NULL, nbytes, 149 1.1 riastrad PROT_READ|PROT_WRITE, MAP_ANON, /*fd*/-1, /*offset*/0)), 150 1.1 riastrad MAP_FAILED); 151 1.1 riastrad 152 1.1 riastrad return ptr; 153 1.1 riastrad } 154 1.1 riastrad 155 1.1 riastrad /* 156 1.1 riastrad * init(stacksize) 157 1.1 riastrad * 158 1.1 riastrad * Initialize state used by various tests with the specified 159 1.1 riastrad * stacksize. 160 1.2 riastrad * 161 1.2 riastrad * Make sure to allocate enough space that even if there shouldn't 162 1.2 riastrad * be a stack guard (i.e., it should be empty), adjusting the 163 1.2 riastrad * requested bounds by the default stack guard size will leave us 164 1.2 riastrad * inside allocated memory. 165 1.1 riastrad */ 166 1.1 riastrad static void 167 1.1 riastrad init(size_t stacksize) 168 1.1 riastrad { 169 1.1 riastrad 170 1.1 riastrad C->size = stacksize; 171 1.2 riastrad C->guardsize = getdefaultguardsize(); 172 1.3 riastrad C->addr = alloc(C->size + C->guardsize); 173 1.1 riastrad RZ(pthread_key_create(&C->jmp_key, NULL)); 174 1.1 riastrad } 175 1.1 riastrad 176 1.1 riastrad /* 177 1.2 riastrad * stack_pointer() 178 1.2 riastrad * 179 1.2 riastrad * Return the stack pointer. This is used to verify whether the 180 1.2 riastrad * stack pointer lie within a certain address range. 181 1.2 riastrad */ 182 1.2 riastrad static __noinline void * 183 1.2 riastrad stack_pointer(void) 184 1.2 riastrad { 185 1.2 riastrad return __builtin_frame_address(0); 186 1.2 riastrad } 187 1.2 riastrad 188 1.2 riastrad /* 189 1.1 riastrad * sigsegv_ok(signo) 190 1.1 riastrad * 191 1.1 riastrad * Signal handler for SIGSEGV to return to the jmp ctx, to verify 192 1.1 riastrad * that SIGSEGV happened without crashing. 193 1.1 riastrad */ 194 1.1 riastrad static void 195 1.1 riastrad sigsegv_ok(int signo) 196 1.1 riastrad { 197 1.1 riastrad struct jmp_ctx *j = pthread_getspecific(C->jmp_key); 198 1.1 riastrad 199 1.1 riastrad longjmp(j->buf, 1); 200 1.1 riastrad } 201 1.1 riastrad 202 1.1 riastrad /* 203 1.1 riastrad * checksigsegv(p) 204 1.1 riastrad * 205 1.1 riastrad * Verify that reading *p triggers SIGSEGV. Fails test nonfatally 206 1.1 riastrad * if SIGSEGV doesn't happen. 207 1.1 riastrad */ 208 1.1 riastrad static void 209 1.1 riastrad checksigsegv(const char *p) 210 1.1 riastrad { 211 1.1 riastrad struct jmp_ctx j; 212 1.1 riastrad struct sigaction act, oact; 213 1.1 riastrad volatile struct sigaction oactsave; 214 1.1 riastrad volatile char v; 215 1.1 riastrad 216 1.1 riastrad memset(&act, 0, sizeof(act)); 217 1.1 riastrad act.sa_handler = &sigsegv_ok; 218 1.1 riastrad 219 1.1 riastrad if (setjmp(j.buf) == 0) { 220 1.4 riastrad pthread_setspecific(C->jmp_key, &j); 221 1.1 riastrad RL(sigaction(SIGSEGV, &act, &oact)); 222 1.1 riastrad oactsave = oact; 223 1.1 riastrad v = *p; /* trigger SIGSEGV */ 224 1.1 riastrad atf_tc_fail_nonfatal("failed to trigger SIGSEGV at %p", p); 225 1.1 riastrad } else { 226 1.1 riastrad /* return from SIGSEGV handler */ 227 1.1 riastrad oact = oactsave; 228 1.1 riastrad } 229 1.1 riastrad RL(sigaction(SIGSEGV, &oact, NULL)); 230 1.1 riastrad pthread_setspecific(C->jmp_key, NULL); 231 1.1 riastrad 232 1.1 riastrad (void)v; /* suppress unused variable warnings */ 233 1.1 riastrad } 234 1.1 riastrad 235 1.1 riastrad /* 236 1.1 riastrad * checknosigsegv(p) 237 1.1 riastrad * 238 1.1 riastrad * Verify that reading *p does not trigger SIGSEGV. Fails test 239 1.1 riastrad * nonfatally if SIGSEGV happens. 240 1.1 riastrad */ 241 1.1 riastrad static void 242 1.1 riastrad checknosigsegv(const char *p) 243 1.1 riastrad { 244 1.1 riastrad struct jmp_ctx j; 245 1.1 riastrad struct sigaction act, oact; 246 1.1 riastrad volatile struct sigaction oactsave; 247 1.1 riastrad volatile char v; 248 1.1 riastrad 249 1.1 riastrad memset(&act, 0, sizeof(act)); 250 1.1 riastrad act.sa_handler = &sigsegv_ok; 251 1.1 riastrad 252 1.1 riastrad if (setjmp(j.buf) == 0) { 253 1.4 riastrad pthread_setspecific(C->jmp_key, &j); 254 1.1 riastrad RL(sigaction(SIGSEGV, &act, &oact)); 255 1.1 riastrad oactsave = oact; 256 1.1 riastrad v = *p; /* better not trigger SIGSEGV */ 257 1.1 riastrad } else { 258 1.1 riastrad /* return from SIGSEGV handler */ 259 1.1 riastrad atf_tc_fail_nonfatal("spuriously triggered SIGSEGV at %p", p); 260 1.1 riastrad oact = oactsave; 261 1.1 riastrad } 262 1.1 riastrad RL(sigaction(SIGSEGV, &oact, NULL)); 263 1.1 riastrad pthread_setspecific(C->jmp_key, NULL); 264 1.1 riastrad 265 1.1 riastrad (void)v; /* suppress unused variable warnings */ 266 1.1 riastrad } 267 1.1 riastrad 268 1.1 riastrad /* 269 1.1 riastrad * checkguardaccessthread(cookie) 270 1.1 riastrad * 271 1.1 riastrad * Thread start routine that verifies it has access to the start 272 1.1 riastrad * and end of its stack, according to pthread_attr_getstack, and 273 1.1 riastrad * _does not_ have access to the start or end of its stack guard, 274 1.1 riastrad * above the stack (in stack growth direction) by 275 1.1 riastrad * pthread_attr_getguardsize bytes. 276 1.1 riastrad */ 277 1.1 riastrad static void * 278 1.1 riastrad checkguardaccessthread(void *cookie) 279 1.1 riastrad { 280 1.1 riastrad pthread_t t = pthread_self(); 281 1.1 riastrad pthread_attr_t attr; 282 1.1 riastrad void *addr, *guard; 283 1.1 riastrad size_t size, guardsize; 284 1.1 riastrad 285 1.1 riastrad /* 286 1.1 riastrad * Get the the stack and stack guard parameters. 287 1.1 riastrad */ 288 1.1 riastrad RZ(pthread_getattr_np(t, &attr)); 289 1.1 riastrad RZ(pthread_attr_getstack(&attr, &addr, &size)); 290 1.1 riastrad RZ(pthread_attr_getguardsize(&attr, &guardsize)); 291 1.1 riastrad 292 1.1 riastrad /* 293 1.1 riastrad * Determine where the guard starts in virtual address space 294 1.1 riastrad * (not in stack growth direction). 295 1.1 riastrad */ 296 1.1 riastrad #ifdef __MACHINE_STACK_GROWS_UP 297 1.1 riastrad guard = (char *)addr + size; 298 1.1 riastrad #else 299 1.1 riastrad guard = (char *)addr - guardsize; 300 1.1 riastrad #endif 301 1.1 riastrad 302 1.1 riastrad /* 303 1.1 riastrad * Verify access to the start and end of the stack itself. 304 1.1 riastrad */ 305 1.1 riastrad checknosigsegv(addr); 306 1.1 riastrad checknosigsegv((char *)addr + size - 1); 307 1.1 riastrad 308 1.1 riastrad /* 309 1.1 riastrad * Verify no access to the start or end of the stack guard. 310 1.1 riastrad */ 311 1.1 riastrad checksigsegv(guard); 312 1.1 riastrad checksigsegv((char *)guard + guardsize - 1); 313 1.1 riastrad 314 1.1 riastrad return NULL; 315 1.1 riastrad } 316 1.1 riastrad 317 1.1 riastrad /* 318 1.1 riastrad * checkaddraccessthread(cookie) 319 1.1 riastrad * 320 1.1 riastrad * Thread start routine that verifies its stack is [C->addr, 321 1.1 riastrad * C->addr + C->size), according to pthread_attr_getstack and 322 1.1 riastrad * pthread_addr_getstacksize, and verifies it has access to that 323 1.1 riastrad * whole range. 324 1.1 riastrad */ 325 1.1 riastrad static void * 326 1.1 riastrad checkaddraccessthread(void *cookie) 327 1.1 riastrad { 328 1.1 riastrad pthread_t t = pthread_self(); 329 1.1 riastrad pthread_attr_t attr; 330 1.2 riastrad void *sp; 331 1.1 riastrad void *addr; 332 1.1 riastrad size_t size, size0; 333 1.1 riastrad 334 1.1 riastrad /* 335 1.2 riastrad * Verify the stack pointer lies somewhere in the allocated 336 1.2 riastrad * range. 337 1.2 riastrad */ 338 1.2 riastrad sp = stack_pointer(); 339 1.2 riastrad ATF_CHECK_MSG(C->addr <= sp, "sp=%p not in [%p,%p + 0x%zu) = [%p,%p)", 340 1.2 riastrad sp, C->addr, C->addr, C->size, C->addr, (char *)C->addr + C->size); 341 1.2 riastrad ATF_CHECK_MSG(sp <= (void *)((char *)C->addr + C->size), 342 1.2 riastrad "sp=%p not in [%p,%p + 0x%zu) = [%p,%p)", 343 1.2 riastrad sp, C->addr, C->addr, C->size, C->addr, (char *)C->addr + C->size); 344 1.2 riastrad 345 1.2 riastrad /* 346 1.2 riastrad * Verify, if not that, then the stack pointer at least lies 347 1.2 riastrad * within the extra buffer we allocated for slop to address a 348 1.2 riastrad * bug NetBSD libpthread used to have of spuriously adding the 349 1.2 riastrad * guard size to a user-allocated stack address. This is 350 1.2 riastrad * ATF_REQUIRE, not ATF_CHECK, because if this doesn't hold, we 351 1.2 riastrad * might be clobbering some other memory like malloc pages, 352 1.2 riastrad * causing the whole test to crash with useless diagnostics. 353 1.2 riastrad */ 354 1.2 riastrad ATF_REQUIRE_MSG(sp <= (void *)((char *)C->addr + C->size + 355 1.2 riastrad C->guardsize), 356 1.2 riastrad "sp=%p not even in buffer [%p,%p + 0x%zu + 0x%zu) = [%p,%p)", 357 1.2 riastrad sp, C->addr, C->addr, C->size, C->guardsize, 358 1.2 riastrad C->addr, (char *)C->addr + C->size + C->guardsize); 359 1.2 riastrad 360 1.2 riastrad /* 361 1.1 riastrad * Get the stack parameters -- both via pthread_attr_getstack 362 1.1 riastrad * and via pthread_attr_getstacksize, to make sure they agree 363 1.1 riastrad * -- and verify that they are what we expect from the caller. 364 1.1 riastrad */ 365 1.1 riastrad RZ(pthread_getattr_np(t, &attr)); 366 1.1 riastrad RZ(pthread_attr_getstack(&attr, &addr, &size)); 367 1.1 riastrad RZ(pthread_attr_getstacksize(&attr, &size0)); 368 1.1 riastrad ATF_CHECK_EQ_MSG(C->addr, addr, "expected %p actual %p", 369 1.1 riastrad C->addr, addr); 370 1.1 riastrad ATF_CHECK_EQ_MSG(C->size, size, "expected %zu actual %zu", 371 1.1 riastrad C->size, size); 372 1.1 riastrad ATF_CHECK_EQ_MSG(C->size, size0, "expected %zu actual %zu", 373 1.1 riastrad C->size, size0); 374 1.1 riastrad 375 1.1 riastrad /* 376 1.1 riastrad * Verify that we have access to what we expect the stack to 377 1.1 riastrad * be. 378 1.1 riastrad */ 379 1.1 riastrad checknosigsegv(C->addr); 380 1.1 riastrad checknosigsegv((char *)C->addr + C->size - 1); 381 1.1 riastrad 382 1.1 riastrad return NULL; 383 1.1 riastrad } 384 1.1 riastrad 385 1.1 riastrad ATF_TC(stack1); 386 1.1 riastrad ATF_TC_HEAD(stack1, tc) 387 1.1 riastrad { 388 1.1 riastrad atf_tc_set_md_var(tc, "descr", 389 1.1 riastrad "Test allocating and reallocating a thread with a user stack"); 390 1.1 riastrad } 391 1.1 riastrad ATF_TC_BODY(stack1, tc) 392 1.1 riastrad { 393 1.1 riastrad pthread_attr_t attr; 394 1.1 riastrad pthread_t t, t2; 395 1.1 riastrad 396 1.1 riastrad /* 397 1.1 riastrad * Allocate a stack with a non-default size to verify 398 1.1 riastrad * libpthread didn't choose the stack size for us. 399 1.1 riastrad */ 400 1.1 riastrad init(getnondefaultstacksize()); 401 1.1 riastrad 402 1.1 riastrad /* 403 1.1 riastrad * Create a thread with user-allocated stack of a non-default 404 1.1 riastrad * size to verify the stack size and access. 405 1.1 riastrad */ 406 1.1 riastrad RZ(pthread_attr_init(&attr)); 407 1.1 riastrad RZ(pthread_attr_setstack(&attr, C->addr, C->size)); 408 1.1 riastrad RZ(pthread_create(&t, &attr, &checkaddraccessthread, C)); 409 1.1 riastrad RZ(pthread_join(t, NULL)); 410 1.1 riastrad 411 1.1 riastrad /* 412 1.1 riastrad * Create another thread with the same parameters, and verify 413 1.1 riastrad * that (a) it was recycled, and (b) it works the same way. 414 1.1 riastrad */ 415 1.1 riastrad RZ(pthread_create(&t2, &attr, &checkaddraccessthread, C)); 416 1.1 riastrad ATF_CHECK_EQ_MSG(t, t2, "t=%p t2=%p", t, t2); /* NetBSD recycles */ 417 1.1 riastrad RZ(pthread_join(t2, NULL)); 418 1.1 riastrad } 419 1.1 riastrad 420 1.1 riastrad ATF_TC(stack2); 421 1.1 riastrad ATF_TC_HEAD(stack2, tc) 422 1.1 riastrad { 423 1.1 riastrad atf_tc_set_md_var(tc, "descr", 424 1.1 riastrad "Test reallocating a thread with a newly self-allocated stack"); 425 1.1 riastrad } 426 1.1 riastrad ATF_TC_BODY(stack2, tc) 427 1.1 riastrad { 428 1.1 riastrad pthread_attr_t attr, attr2; 429 1.1 riastrad size_t size, size2; 430 1.1 riastrad pthread_t t, t2; 431 1.1 riastrad 432 1.1 riastrad /* 433 1.1 riastrad * Allocate a stack with the default size so that we verify 434 1.1 riastrad * when libpthread reuses the thread, it doesn't inadvertently 435 1.1 riastrad * reuse the libpthread-allocated stack too and instead 436 1.1 riastrad * correctly uses our user-allocated stack. 437 1.1 riastrad */ 438 1.1 riastrad init(getdefaultstacksize()); 439 1.1 riastrad 440 1.1 riastrad /* 441 1.1 riastrad * Create a thread with a libpthread-allocated stack that 442 1.1 riastrad * verifies 443 1.1 riastrad * (a) access to its own stack, and 444 1.1 riastrad * (b) no access to its own guard pages; 445 1.1 riastrad * then get its attributes and wait for it to complete. 446 1.1 riastrad */ 447 1.1 riastrad RZ(pthread_create(&t, NULL, &checkguardaccessthread, C)); 448 1.1 riastrad RZ(pthread_getattr_np(t, &attr)); 449 1.1 riastrad RZ(pthread_join(t, NULL)); 450 1.1 riastrad 451 1.1 riastrad /* 452 1.1 riastrad * Create a thread with a user-allocated stack that verifies 453 1.1 riastrad * (a) stack addr/size match request, and 454 1.1 riastrad * (b) access to the requested stack, 455 1.1 riastrad * and confirm that the first thread was recycled -- not part 456 1.1 riastrad * of POSIX semantics, but part of NetBSD's implementation; 457 1.1 riastrad * this way, we verify that, even though the thread is 458 1.1 riastrad * recycled, the thread's stack is set to the user-allocated 459 1.1 riastrad * stack and access to it works as expected. Then wait for it 460 1.1 riastrad * to complete. 461 1.1 riastrad */ 462 1.1 riastrad RZ(pthread_attr_init(&attr2)); 463 1.1 riastrad RZ(pthread_attr_setstack(&attr2, C->addr, C->size)); 464 1.1 riastrad RZ(pthread_create(&t2, &attr2, &checkaddraccessthread, C)); 465 1.1 riastrad ATF_CHECK_EQ_MSG(t, t2, "t=%p t2=%p", t, t2); /* NetBSD recycles */ 466 1.1 riastrad RZ(pthread_join(t2, NULL)); 467 1.1 riastrad 468 1.1 riastrad /* 469 1.1 riastrad * Verify that the libpthread-allocated stack and 470 1.1 riastrad * user-allocated stack had the same size, since we chose the 471 1.1 riastrad * default size. 472 1.1 riastrad * 473 1.1 riastrad * Note: We can't say anything about the guard size, because 474 1.1 riastrad * with pthread_attr_setstack, the guard size is ignored, and 475 1.1 riastrad * it's not clear from POSIX whether any meaningful guard size 476 1.1 riastrad * is stored for retrieval with pthread_attr_getguardsize in 477 1.1 riastrad * attributes with pthread_attr_setstack. 478 1.1 riastrad */ 479 1.1 riastrad RZ(pthread_attr_getstacksize(&attr, &size)); 480 1.1 riastrad RZ(pthread_attr_getstacksize(&attr2, &size2)); 481 1.1 riastrad ATF_CHECK_EQ_MSG(size, size2, "size=%zu size2=%zu", size, size2); 482 1.1 riastrad } 483 1.1 riastrad 484 1.1 riastrad ATF_TP_ADD_TCS(tp) 485 1.1 riastrad { 486 1.1 riastrad 487 1.1 riastrad ATF_TP_ADD_TC(tp, stack1); 488 1.1 riastrad ATF_TP_ADD_TC(tp, stack2); 489 1.1 riastrad 490 1.1 riastrad return atf_no_error(); 491 1.1 riastrad } 492