t_signal_and_sp.c revision 1.9 1 /* $NetBSD: t_signal_and_sp.c,v 1.9 2025/04/21 03:48:07 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 2024 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: t_signal_and_sp.c,v 1.9 2025/04/21 03:48:07 riastradh Exp $");
31
32 #include <sys/wait.h>
33
34 #include <machine/param.h>
35
36 #include <atf-c.h>
37 #include <limits.h>
38 #include <poll.h>
39 #include <pthread.h>
40 #include <signal.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <time.h>
45 #include <ucontext.h>
46 #include <unistd.h>
47
48 #include "h_execsp.h"
49 #include "h_macros.h"
50
51 #ifdef HAVE_STACK_POINTER_H
52 # include "stack_pointer.h"
53 #endif
54
55 #ifdef HAVE_SIGNALSPHANDLER
56 void signalsphandler(int); /* signalsphandler.S assembly routine */
57 #endif
58
59 void *volatile signalsp;
60
61 static void
62 test_execsp(const struct atf_tc *tc, const char *prog)
63 {
64 #ifdef STACK_ALIGNBYTES
65 char h_execsp[PATH_MAX];
66 struct execsp execsp;
67 int fd[2];
68 pid_t pid;
69 struct pollfd pollfd;
70 int nfds;
71 ssize_t nread;
72 int status;
73
74 /*
75 * Determine the full path to the helper program.
76 */
77 RL(snprintf(h_execsp, sizeof(h_execsp), "%s/%s",
78 atf_tc_get_config_var(tc, "srcdir"), prog));
79
80 /*
81 * Create a pipe to read a bundle of stack pointer samples from
82 * the child, and fork the child.
83 */
84 RL(pipe(fd));
85 RL(pid = vfork());
86 if (pid == 0) { /* child */
87 char *const argv[] = {h_execsp, NULL};
88
89 if (dup2(fd[1], STDOUT_FILENO) == -1)
90 _exit(1);
91 if (closefrom(STDERR_FILENO + 1) == -1)
92 _exit(2);
93 if (execve(argv[0], argv, NULL) == -1)
94 _exit(3);
95 _exit(4);
96 }
97
98 /*
99 * Close the writing end so, if something goes wrong in the
100 * child, we don't hang indefinitely waiting for output.
101 */
102 RL(close(fd[1]));
103
104 /*
105 * Wait up to 5sec for the child to return an answer. Any more
106 * than that, and we kill it. The child is mostly hand-written
107 * assembly routines where lots can go wrong, so don't bother
108 * waiting if it gets stuck in a loop.
109 */
110 pollfd.fd = fd[0];
111 pollfd.events = POLLIN;
112 RL(nfds = poll(&pollfd, 1, 5*1000/*ms*/));
113 if (nfds == 0) {
114 fprintf(stderr, "child hung, killing\n");
115 RL(kill(pid, SIGKILL));
116 }
117
118 /*
119 * Read a bundle of stack pointer samples from the child.
120 */
121 RL(nread = read(fd[0], &execsp, sizeof(execsp)));
122 ATF_CHECK_MSG((size_t)nread == sizeof(execsp),
123 "nread=%zu sizeof(execsp)=%zu",
124 (size_t)nread, sizeof(execsp));
125
126 /*
127 * Wait for the child to terminate and report failure if it
128 * didn't exit cleanly.
129 */
130 RL(waitpid(pid, &status, 0));
131 if (WIFSIGNALED(status)) {
132 atf_tc_fail_nonfatal("child exited on signal %d (%s)",
133 WTERMSIG(status), strsignal(WTERMSIG(status)));
134 } else if (!WIFEXITED(status)) {
135 atf_tc_fail_nonfatal("child exited status=0x%x", status);
136 } else {
137 ATF_CHECK_MSG(WEXITSTATUS(status) == 0,
138 "child exited with code %d",
139 WEXITSTATUS(status));
140 }
141
142 /*
143 * Now that we have reaped the child, stop here if the stack
144 * pointer samples are bogus; otherwise verify they are all
145 * aligned.
146 */
147 if ((size_t)nread != sizeof(execsp))
148 return; /* failed already */
149
150 printf("start sp @ %p\n", execsp.startsp);
151 printf("ctor sp @ %p\n", execsp.ctorsp);
152 printf("main sp @ %p\n", execsp.mainsp);
153 printf("dtor sp @ %p\n", execsp.dtorsp);
154
155 ATF_CHECK_MSG(((uintptr_t)execsp.startsp & STACK_ALIGNBYTES) == 0,
156 "elf entry point was called with misaligned sp: %p",
157 execsp.startsp);
158
159 ATF_CHECK_MSG(((uintptr_t)execsp.ctorsp & STACK_ALIGNBYTES) == 0,
160 "elf constructor was called with misaligned sp: %p",
161 execsp.ctorsp);
162
163 ATF_CHECK_MSG(((uintptr_t)execsp.mainsp & STACK_ALIGNBYTES) == 0,
164 "main function was called with misaligned sp: %p",
165 execsp.mainsp);
166
167 ATF_CHECK_MSG(((uintptr_t)execsp.dtorsp & STACK_ALIGNBYTES) == 0,
168 "elf destructor was called with misaligned sp: %p",
169 execsp.dtorsp);
170
171 /*
172 * Leave a reminder on architectures for which we haven't
173 * implemented execsp_start.S.
174 */
175 if (execsp.startsp == NULL ||
176 execsp.ctorsp == NULL ||
177 execsp.mainsp == NULL ||
178 execsp.dtorsp == NULL)
179 atf_tc_skip("Not fully supported on this architecture");
180 #else
181 atf_tc_skip("Unknown STACK_ALIGNBYTES on this architecture");
182 #endif
183 }
184
185 ATF_TC(execsp_dynamic);
186 ATF_TC_HEAD(execsp_dynamic, tc)
187 {
188 atf_tc_set_md_var(tc, "descr",
189 "Verify stack pointer is aligned on dynamic program start");
190 }
191 ATF_TC_BODY(execsp_dynamic, tc)
192 {
193 test_execsp(tc, "h_execsp_dynamic");
194 }
195
196 ATF_TC(execsp_static);
197 ATF_TC_HEAD(execsp_static, tc)
198 {
199 atf_tc_set_md_var(tc, "descr",
200 "Verify stack pointer is aligned on static program start");
201 }
202 ATF_TC_BODY(execsp_static, tc)
203 {
204 test_execsp(tc, "h_execsp_static");
205 }
206
207 #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
208 void *volatile contextsp; /* set by contextspfunc.S */
209 static ucontext_t return_context;
210 static volatile bool test_context_done;
211
212 void contextspfunc(void); /* contextspfunc.S assembly routine */
213
214 static void
215 contextnoop(void)
216 {
217
218 fprintf(stderr, "contextnoop\n");
219 /* control will return to contextspfunc via uc_link */
220 }
221
222 void contextdone(void); /* called by contextspfunc.S */
223 void
224 contextdone(void)
225 {
226
227 fprintf(stderr, "contextdone\n");
228 ATF_REQUIRE(!test_context_done);
229 test_context_done = true;
230 RL(setcontext(&return_context));
231 atf_tc_fail("setcontext returned");
232 }
233 #endif
234
235 ATF_TC(contextsp);
236 ATF_TC_HEAD(contextsp, tc)
237 {
238 atf_tc_set_md_var(tc, "descr",
239 "Verify stack pointer is aligned on makecontext entry");
240 }
241 ATF_TC_BODY(contextsp, tc)
242 {
243 #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
244 ucontext_t uc;
245 char *stack;
246 unsigned i;
247
248 #ifdef __hppa__
249 /*
250 * Not sure what the deal is but I probably wrote contextspfunc
251 * wrong.
252 */
253 atf_tc_expect_signal(SIGILL, "PR kern/59327:"
254 " user stack pointer is not aligned properly");
255 #endif
256
257 REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
258 fprintf(stderr, "stack @ [%p,%p)\n", stack,
259 stack + SIGSTKSZ + STACK_ALIGNBYTES);
260
261 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
262 contextsp = NULL;
263 test_context_done = false;
264
265 RL(getcontext(&uc));
266 uc.uc_stack.ss_sp = stack;
267 uc.uc_stack.ss_size = SIGSTKSZ + i;
268 makecontext(&uc, &contextspfunc, 0);
269
270 fprintf(stderr, "[%u] swapcontext\n", i);
271 RL(swapcontext(&return_context, &uc));
272
273 ATF_CHECK(contextsp != NULL);
274 ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)contextsp &&
275 (uintptr_t)contextsp <= (uintptr_t)stack + SIGSTKSZ + i,
276 "contextsp=%p", contextsp);
277 ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
278 "[%u] makecontext function called with misaligned sp %p",
279 i, contextsp);
280 }
281
282 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
283 contextsp = NULL;
284 test_context_done = false;
285
286 RL(getcontext(&uc));
287 uc.uc_stack.ss_sp = stack + i;
288 uc.uc_stack.ss_size = SIGSTKSZ;
289 makecontext(&uc, &contextspfunc, 0);
290
291 fprintf(stderr, "[%u] swapcontext\n", i);
292 RL(swapcontext(&return_context, &uc));
293
294 ATF_CHECK(contextsp != NULL);
295 ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)contextsp &&
296 (uintptr_t)contextsp <= (uintptr_t)stack + i + SIGSTKSZ,
297 "contextsp=%p", contextsp);
298 ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
299 "[%u] makecontext function called with misaligned sp %p",
300 i, contextsp);
301 }
302 #else
303 atf_tc_skip("Not implemented on this platform");
304 #endif
305 }
306
307 ATF_TC(contextsplink);
308 ATF_TC_HEAD(contextsplink, tc)
309 {
310 atf_tc_set_md_var(tc, "descr",
311 "Verify stack pointer is aligned on makecontext link entry");
312 }
313 ATF_TC_BODY(contextsplink, tc)
314 {
315 #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC
316 ucontext_t uc1, uc2;
317 char *stack1, *stack2;
318 unsigned i;
319
320 REQUIRE_LIBC(stack1 = malloc(SIGSTKSZ), NULL);
321 fprintf(stderr, "stack1 @ [%p,%p)\n", stack1, stack1 + SIGSTKSZ);
322 REQUIRE_LIBC(stack2 = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
323 fprintf(stderr, "stack2 @ [%p,%p)\n",
324 stack2, stack2 + SIGSTKSZ + STACK_ALIGNBYTES);
325
326 #ifdef __hppa__
327 /*
328 * Not sure what the deal is but I probably wrote contextspfunc
329 * wrong.
330 */
331 atf_tc_expect_signal(SIGILL, "PR kern/59327:"
332 " user stack pointer is not aligned properly");
333 #endif
334 #ifdef __mips_n64
335 atf_tc_expect_fail("PR kern/59327:"
336 " user stack pointer is not aligned properly");
337 #endif
338
339 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
340 contextsp = NULL;
341 test_context_done = false;
342
343 RL(getcontext(&uc1));
344 uc1.uc_stack.ss_sp = stack1;
345 uc1.uc_stack.ss_size = SIGSTKSZ;
346 uc1.uc_link = &uc2;
347 makecontext(&uc1, &contextnoop, 0);
348
349 RL(getcontext(&uc2));
350 uc2.uc_stack.ss_sp = stack2;
351 uc2.uc_stack.ss_size = SIGSTKSZ + i;
352 makecontext(&uc2, &contextspfunc, 0);
353
354 fprintf(stderr, "[%u] swapcontext\n", i);
355 RL(swapcontext(&return_context, &uc1));
356
357 ATF_CHECK(contextsp != NULL);
358 ATF_CHECK_MSG((uintptr_t)stack2 <= (uintptr_t)contextsp &&
359 (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i,
360 "contextsp=%p", contextsp);
361 ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
362 "[%u] makecontext function called with misaligned sp %p",
363 i, contextsp);
364 }
365
366 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
367 contextsp = NULL;
368 test_context_done = false;
369
370 RL(getcontext(&uc1));
371 uc1.uc_stack.ss_sp = stack1;
372 uc1.uc_stack.ss_size = SIGSTKSZ;
373 uc1.uc_link = &uc2;
374 makecontext(&uc1, &contextnoop, 0);
375
376 RL(getcontext(&uc2));
377 uc2.uc_stack.ss_sp = stack2 + i;
378 uc2.uc_stack.ss_size = SIGSTKSZ;
379 makecontext(&uc2, &contextspfunc, 0);
380
381 fprintf(stderr, "[%u] swapcontext\n", i);
382 RL(swapcontext(&return_context, &uc1));
383
384 ATF_CHECK(contextsp != NULL);
385 ATF_CHECK_MSG((uintptr_t)stack2 + i <= (uintptr_t)contextsp &&
386 (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i,
387 "contextsp=%p", contextsp);
388 ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0,
389 "[%u] makecontext function called with misaligned sp %p",
390 i, contextsp);
391 }
392 #else
393 atf_tc_skip("Not implemented on this platform");
394 #endif
395 }
396
397 ATF_TC(signalsp);
398 ATF_TC_HEAD(signalsp, tc)
399 {
400 atf_tc_set_md_var(tc, "descr",
401 "Verify stack pointer is aligned on entry to signal handler");
402 }
403 ATF_TC_BODY(signalsp, tc)
404 {
405 #if defined STACK_ALIGNBYTES && defined HAVE_SIGNALSPHANDLER
406 struct sigaction sa;
407
408 memset(&sa, 0, sizeof(sa));
409 sa.sa_handler = &signalsphandler;
410 RL(sigaction(SIGUSR1, &sa, NULL));
411 RL(raise(SIGUSR1));
412
413 ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
414 "signal handler was called with a misaligned sp: %p",
415 signalsp);
416 #else
417 atf_tc_skip("Not implemented on this platform");
418 #endif
419 }
420
421 ATF_TC(signalsp_sigaltstack);
422 ATF_TC_HEAD(signalsp_sigaltstack, tc)
423 {
424 atf_tc_set_md_var(tc, "descr",
425 "Verify stack pointer is aligned on entry to signal handler"
426 " with maximally misaligned sigaltstack");
427 }
428 ATF_TC_BODY(signalsp_sigaltstack, tc)
429 {
430 #if defined STACK_ALIGNBYTES && HAVE_SIGNALSPHANDLER
431 char *stack;
432 struct sigaction sa;
433 struct sigaltstack ss;
434 unsigned i;
435
436 memset(&sa, 0, sizeof(sa));
437 sa.sa_handler = &signalsphandler;
438 sa.sa_flags = SA_ONSTACK;
439 RL(sigaction(SIGUSR1, &sa, NULL));
440
441 /*
442 * Allocate a signal stack with enough slop to try all possible
443 * misalignments of the stack pointer. Print it to stderr so
444 * it always appears in atf output before shenanigans happen.
445 */
446 REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
447 fprintf(stderr, "stack @ [%p, %p)\n",
448 stack, stack + SIGSTKSZ + STACK_ALIGNBYTES);
449
450 #if defined __alpha__ || defined __i386__ || defined __mips__
451 atf_tc_expect_fail("PR kern/59327:"
452 " user stack pointer is not aligned properly");
453 #endif
454
455 /*
456 * Try with all alignments of high addresses.
457 */
458 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
459 ss.ss_sp = stack;
460 ss.ss_size = SIGSTKSZ + i;
461 ss.ss_flags = 0;
462 RL(sigaltstack(&ss, NULL));
463
464 signalsp = NULL;
465 RL(raise(SIGUSR1));
466 ATF_CHECK(signalsp != NULL);
467 ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)signalsp &&
468 (uintptr_t)signalsp <= (uintptr_t)stack + SIGSTKSZ + i,
469 "signalsp=%p", signalsp);
470 ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
471 "[%u] signal handler was called with a misaligned sp: %p",
472 i, signalsp);
473 }
474
475 /*
476 * Try with all alignments of low addresses.
477 */
478 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
479 ss.ss_sp = stack + i;
480 ss.ss_size = SIGSTKSZ;
481 ss.ss_flags = 0;
482 RL(sigaltstack(&ss, NULL));
483
484 signalsp = NULL;
485 RL(raise(SIGUSR1));
486 ATF_CHECK(signalsp != NULL);
487 ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)signalsp &&
488 (uintptr_t)signalsp <= (uintptr_t)stack + i + SIGSTKSZ,
489 "signalsp=%p", signalsp);
490 ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
491 "[%u] signal handler was called with a misaligned sp: %p",
492 i, signalsp);
493 }
494 #else
495 atf_tc_skip("Not implemented on this platform");
496 #endif
497 }
498
499 #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC
500 void *threadspfunc(void *); /* threadspfunc.S assembly routine */
501 #endif
502
503 ATF_TC(threadsp);
504 ATF_TC_HEAD(threadsp, tc)
505 {
506 atf_tc_set_md_var(tc, "descr",
507 "Verify stack pointer is aligned on thread start");
508 }
509 ATF_TC_BODY(threadsp, tc)
510 {
511 #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC
512 char *stack;
513 unsigned i;
514
515 REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL);
516 fprintf(stderr, "stack @ [%p,%p)\n", stack,
517 stack + SIGSTKSZ + STACK_ALIGNBYTES);
518
519 #ifdef __hppa__
520 /*
521 * Not sure what the deal is but I probably wrote threadspfunc
522 * wrong.
523 */
524 atf_tc_expect_signal(SIGBUS, "PR kern/59327:"
525 " user stack pointer is not aligned properly");
526 #endif
527 #ifdef __riscv__
528 atf_tc_expect_fail("sp inexplicably lies outside stack range");
529 #endif
530
531 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
532 pthread_t t;
533 pthread_attr_t attr;
534 void *sp;
535
536 RZ(pthread_attr_init(&attr));
537 RZ(pthread_attr_setstack(&attr, stack, SIGSTKSZ + i));
538 RZ(pthread_create(&t, &attr, &threadspfunc, NULL));
539 RZ(pthread_attr_destroy(&attr));
540
541 alarm(1);
542 RZ(pthread_join(t, &sp));
543 alarm(0);
544
545 ATF_CHECK(sp != NULL);
546 ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)sp &&
547 (uintptr_t)sp <= (uintptr_t)stack + SIGSTKSZ + i,
548 "sp=%p", sp);
549 ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
550 "[%u] thread called with misaligned sp: %p", i, signalsp);
551 }
552
553 for (i = 0; i <= STACK_ALIGNBYTES; i++) {
554 pthread_t t;
555 pthread_attr_t attr;
556 void *sp;
557
558 RZ(pthread_attr_init(&attr));
559 RZ(pthread_attr_setstack(&attr, stack + i, SIGSTKSZ));
560 RZ(pthread_create(&t, &attr, &threadspfunc, NULL));
561 RZ(pthread_attr_destroy(&attr));
562
563 alarm(1);
564 RZ(pthread_join(t, &sp));
565 alarm(0);
566
567 ATF_CHECK(sp != NULL);
568 ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)sp &&
569 (uintptr_t)sp <= (uintptr_t)stack + i + SIGSTKSZ,
570 "sp=%p", sp);
571 ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
572 "[%u] thread called with misaligned sp: %p", i, signalsp);
573 }
574 #else
575 atf_tc_skip("Not implemented on this platform");
576 #endif
577 }
578
579 ATF_TC(misaligned_sp_and_signal);
580 ATF_TC_HEAD(misaligned_sp_and_signal, tc)
581 {
582 atf_tc_set_md_var(tc, "descr", "process can return from a signal"
583 " handler even if the stack pointer is misaligned when a signal"
584 " arrives");
585 }
586 ATF_TC_BODY(misaligned_sp_and_signal, tc)
587 {
588 #if defined STACK_ALIGNBYTES && defined HAVE_STACK_POINTER_H
589 /*
590 * Set up a handler for SIGALRM.
591 */
592 struct sigaction sa;
593 memset(&sa, 0, sizeof(sa));
594 sa.sa_handler = &signalsphandler;
595 RL(sigaction(SIGALRM, &sa, NULL));
596
597 #if defined __alpha__ || defined __i386__ || defined __mips__
598 atf_tc_expect_fail("PR kern/58149:"
599 " Cannot return from a signal handler"
600 " if SP was misaligned when the signal arrived");
601 #endif
602
603 /*
604 * Set up an interval timer so that we receive SIGALRM after 50 ms.
605 */
606 struct itimerval itv;
607 memset(&itv, 0, sizeof(itv));
608 itv.it_value.tv_usec = 1000 * 50;
609 RL(setitimer(ITIMER_MONOTONIC, &itv, NULL));
610
611 /*
612 * Now misalign the SP. Wait for the signal to arrive and see what
613 * happens. This should be fine as long as we don't use it to
614 * access memory.
615 */
616 MISALIGN_SP;
617 while (signalsp == NULL) {
618 /*
619 * Make sure the compiler does not optimize this busy loop
620 * away.
621 */
622 __asm__("" ::: "memory");
623 }
624 /*
625 * We could successfully return from a signal handler. Now we
626 * should fix the SP before calling any functions.
627 */
628 FIX_SP;
629
630 /*
631 * But was the stack pointer aligned when we were on the signal
632 * handler?
633 */
634 ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0,
635 "signal handler was called with a misaligned sp: %p",
636 signalsp);
637 #else
638 atf_tc_skip("Not implemented for this platform");
639 #endif
640 }
641
642 ATF_TP_ADD_TCS(tp)
643 {
644
645 ATF_TP_ADD_TC(tp, contextsp);
646 ATF_TP_ADD_TC(tp, contextsplink);
647 ATF_TP_ADD_TC(tp, execsp_dynamic);
648 ATF_TP_ADD_TC(tp, execsp_static);
649 ATF_TP_ADD_TC(tp, misaligned_sp_and_signal);
650 ATF_TP_ADD_TC(tp, signalsp);
651 ATF_TP_ADD_TC(tp, signalsp_sigaltstack);
652 ATF_TP_ADD_TC(tp, threadsp);
653 return atf_no_error();
654 }
655