1 #include <darwintest.h>
4 #include <mach/mach_types.h>
7 #include <dispatch/dispatch.h>
9 typedef enum { PTHREAD
, WORKQUEUE
} thread_type_t
;
20 corrupt_type_t corrupt_type
= (corrupt_type_t
)ctx
;
21 pthread_t self
= pthread_self();
23 T_LOG("Helper thread running: %d", corrupt_type
);
25 // The pthread_t is stored at the top of the stack and could be
26 // corrupted because of a stack overflow. To make the test more
27 // reliable, we will manually smash the pthread struct directly.
28 switch (corrupt_type
) {
32 memset(self
, 0x41, 128);
34 case FULL_CORRUPTION
: /* includes TSD */
35 memset(self
, 0x41, 4096);
39 // Expected behavior is that if a thread calls abort, the process should
42 T_FAIL("Abort didn't?");
46 abort_test(thread_type_t type
, corrupt_type_t corrupt_type
)
51 T_LOG("Child running");
57 pthread_create(&tid
, NULL
, body
, (void *)corrupt_type
), NULL
);
61 dispatch_async_f(dispatch_get_global_queue(
62 DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0),
63 (void *)corrupt_type
, &body
);
68 T_FAIL("Child didn't abort");
72 // Wait and check the exit status of the child
74 pid_t pid
= wait(&status
);
76 T_ASSERT_EQ(pid
, child
, NULL
);
78 T_EXPECT_FALSE(WIFEXITED(status
), "WIFEXITED Status: %x", status
);
80 T_EXPECT_TRUE(WIFSIGNALED(status
), "WIFSIGNALED Status: %x", status
);
82 T_EXPECT_FALSE(WIFSTOPPED(status
), "WIFSTOPPED Status: %x", status
);
84 // This test is successful if we trigger a SIGSEGV|SIGBUS or SIGABRT
85 // since both will promptly terminate the program
86 int signal
= WTERMSIG(status
);
88 #if defined(__i386__) || defined(__x86_64__)
89 // on intel pthread_self() reads a TSD so FULL corruption results
91 if (corrupt_type
== FULL_CORRUPTION
) {
92 // any of these signals may happen depending on which libpthread
94 if (signal
== SIGBUS
) {
95 T_LOG("Converting %d to SIGSEGV", signal
);
98 T_EXPECT_EQ(signal
, SIGSEGV
, NULL
);
103 /* pthread calls abort_with_reason if only the signature is corrupt */
104 T_EXPECT_EQ(signal
, SIGABRT
, NULL
);
108 signal_handler(int signo
)
110 // The user's signal handler should not be called during abort
111 T_FAIL("Unexpected signal: %d\n", signo
);
114 T_DECL(abort_pthread_corrupt_test_full
, "Tests abort")
116 abort_test(PTHREAD
, FULL_CORRUPTION
);
119 T_DECL(abort_workqueue_corrupt_test_full
, "Tests abort")
121 abort_test(WORKQUEUE
, FULL_CORRUPTION
);
124 T_DECL(abort_pthread_handler_test_full
, "Tests abort")
127 T_SKIP("Abort hangs if the user registers their own SIGSEGV handler");
128 signal(SIGSEGV
, signal_handler
);
129 abort_test(PTHREAD
, FULL_CORRUPTION
);
132 T_DECL(abort_workqueue_handler_test_full
, "Tests abort")
135 T_SKIP("Abort hangs if the user registers their own SIGSEGV handler");
136 signal(SIGSEGV
, signal_handler
);
137 abort_test(WORKQUEUE
, FULL_CORRUPTION
);
140 T_DECL(abort_pthread_corrupt_test_sig
, "Tests abort")
142 abort_test(PTHREAD
, SIG_CORRUPTION
);
145 T_DECL(abort_workqueue_corrupt_test_sig
, "Tests abort")
147 abort_test(WORKQUEUE
, SIG_CORRUPTION
);
150 T_DECL(abort_pthread_test
, "Tests abort")
152 abort_test(PTHREAD
, NO_CORRUPTION
);
155 T_DECL(abort_workqueue_test
, "Tests abort")
157 abort_test(WORKQUEUE
, NO_CORRUPTION
);