]> git.saurik.com Git - apple/libc.git/blob - tests/abort_tests.c
Libc-1353.41.1.tar.gz
[apple/libc.git] / tests / abort_tests.c
1 #include <darwintest.h>
2 #include <sys/types.h>
3 #include <pthread.h>
4 #include <mach/mach_types.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <dispatch/dispatch.h>
8
9 static void *
10 body(void *corrupt)
11 {
12 T_LOG("Helper thread running: %d", (bool)corrupt);
13 if (corrupt) {
14 // The pthread_t is stored at the top of the stack and could be
15 // corrupted because of a stack overflow. To make the test more
16 // reliable, we will manually smash the pthread struct directly.
17 pthread_t self = pthread_self();
18 memset(self, 0x41, 4096);
19 }
20 // Expected behavior is that if a thread calls abort, the process should
21 // abort promptly.
22 abort();
23 T_FAIL("Abort didn't?");
24 }
25
26 typedef enum { PTHREAD, WORKQUEUE } thread_type_t;
27
28 static void
29 abort_test(thread_type_t type, int expected_signal)
30 {
31 pid_t child = fork();
32 bool corrupt = expected_signal == SIGSEGV;
33
34 if (child == 0) {
35 T_LOG("Child running");
36 switch (type) {
37 case PTHREAD: {
38 pthread_t tid;
39 T_QUIET;
40 T_ASSERT_POSIX_ZERO(
41 pthread_create(&tid, NULL, body, (void *)corrupt), NULL);
42 break;
43 }
44 case WORKQUEUE: {
45 dispatch_async_f(dispatch_get_global_queue(
46 DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
47 (void *)corrupt, &body);
48 break;
49 }
50 }
51 sleep(5);
52 T_FAIL("Child didn't abort");
53 exit(-1);
54 } else {
55 // Wait and check the exit status of the child
56 int status = 0;
57 pid_t pid = wait(&status);
58 T_QUIET;
59 T_ASSERT_EQ(pid, child, NULL);
60 T_QUIET;
61 T_EXPECT_FALSE(WIFEXITED(status), "WIFEXITED Status: %x", status);
62 T_QUIET;
63 T_EXPECT_TRUE(WIFSIGNALED(status), "WIFSIGNALED Status: %x", status);
64 T_QUIET;
65 T_EXPECT_FALSE(WIFSTOPPED(status), "WIFSTOPPED Status: %x", status);
66 // This test is successful if we trigger a SIGSEGV|SIGBUS or SIGABRT
67 // since both will promptly terminate the program
68 int signal = WTERMSIG(status);
69 if (signal == SIGBUS) {
70 // rdar://53269061
71 T_LOG("Converting %d to SIGSEGV", signal);
72 signal = SIGSEGV;
73 }
74 T_EXPECT_EQ(signal, expected_signal, NULL);
75 }
76 }
77
78 static void
79 signal_handler(int signo)
80 {
81 // The user's signal handler should not be called during abort
82 T_FAIL("Unexpected signal: %d\n", signo);
83 }
84
85 T_DECL(abort_pthread_corrupt_test, "Tests abort")
86 {
87 abort_test(PTHREAD, SIGSEGV);
88 }
89
90 T_DECL(abort_workqueue_corrupt_test, "Tests abort")
91 {
92 abort_test(WORKQUEUE, SIGSEGV);
93 }
94
95 T_DECL(abort_pthread_handler_test, "Tests abort")
96 {
97 // rdar://52892057
98 T_SKIP("Abort hangs if the user registers their own SIGSEGV handler");
99 signal(SIGSEGV, signal_handler);
100 abort_test(PTHREAD, SIGSEGV);
101 }
102
103 T_DECL(abort_workqueue_handler_test, "Tests abort")
104 {
105 // rdar://52892057
106 T_SKIP("Abort hangs if the user registers their own SIGSEGV handler");
107 signal(SIGSEGV, signal_handler);
108 abort_test(WORKQUEUE, SIGSEGV);
109 }
110
111 T_DECL(abort_pthread_test, "Tests abort")
112 {
113 abort_test(PTHREAD, SIGABRT);
114 }
115
116 T_DECL(abort_workqueue_test, "Tests abort")
117 {
118 abort_test(WORKQUEUE, SIGABRT);
119 }