6 #include <darwintest.h>
7 #include <dispatch/dispatch.h>
10 #include <spawn_private.h>
12 #include <mach-o/dyld.h>
13 #include <mach/mach.h>
14 #include <mach/task.h>
17 #include <sys/sysctl.h>
18 #include <sys/syslimits.h>
20 #include <excserver.h>
22 static dispatch_semaphore_t sync_sema
;
25 catch_mach_exception_raise(mach_port_t exception_port
,
28 exception_type_t exception
,
29 mach_exception_data_t code
,
30 mach_msg_type_number_t code_count
)
32 #pragma unused(exception_port, thread, task, code, code_count)
34 pid_for_task(task
, &pid
);
35 T_ASSERT_EQ(exception
, EXC_CORPSE_NOTIFY
, "exception type");
36 T_ASSERT_POSIX_ZERO(kill(pid
, SIGKILL
), "kill");
37 dispatch_semaphore_signal(sync_sema
);
42 catch_mach_exception_raise_state(mach_port_t exception_port
,
43 exception_type_t exception
,
44 const mach_exception_data_t code
,
45 mach_msg_type_number_t code_count
,
47 const thread_state_t old_state
,
48 mach_msg_type_number_t old_state_count
,
49 thread_state_t new_state
,
50 mach_msg_type_number_t
* new_state_count
)
52 #pragma unused(exception_port, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
53 T_FAIL("Unsupported catch_mach_exception_raise_state");
54 return KERN_NOT_SUPPORTED
;
58 catch_mach_exception_raise_state_identity(mach_port_t exception_port
,
61 exception_type_t exception
,
62 mach_exception_data_t code
,
63 mach_msg_type_number_t code_count
,
65 thread_state_t old_state
,
66 mach_msg_type_number_t old_state_count
,
67 thread_state_t new_state
,
68 mach_msg_type_number_t
* new_state_count
)
70 #pragma unused(exception_port, thread, task, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
71 T_FAIL("Unsupported catch_mach_exception_raise_state_identity");
72 return KERN_NOT_SUPPORTED
;
77 * setup exception handling port for EXC_CORPSE_NOTIFY.
78 * runs mach_msg_server once for receiving exception messages from kernel.
81 exc_handler(void * arg
)
85 mach_port_t exception_port
;
87 kret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &exception_port
);
88 if (kret
!= KERN_SUCCESS
) {
89 T_FAIL("mach_port_allocate: %s (%d)", mach_error_string(kret
), kret
);
92 kret
= mach_port_insert_right(mach_task_self(), exception_port
, exception_port
, MACH_MSG_TYPE_MAKE_SEND
);
93 if (kret
!= KERN_SUCCESS
) {
94 T_FAIL("mach_port_insert_right: %s (%d)", mach_error_string(kret
), kret
);
97 kret
= task_set_exception_ports(mach_task_self(), EXC_MASK_CRASH
| EXC_MASK_CORPSE_NOTIFY
, exception_port
,
98 (exception_behavior_t
)(EXCEPTION_DEFAULT
| MACH_EXCEPTION_CODES
), 0);
99 if (kret
!= KERN_SUCCESS
) {
100 T_FAIL("task_set_exception_ports: %s (%d)", mach_error_string(kret
), kret
);
103 dispatch_semaphore_signal(sync_sema
);
105 kret
= mach_msg_server(mach_exc_server
, MACH_MSG_SIZE_RELIABLE
, exception_port
, 0);
106 if (kret
!= KERN_SUCCESS
) {
107 T_FAIL("mach_msg_server: %s (%d)", mach_error_string(kret
), kret
);
114 dummy_thread(void *arg
)
122 #define THREAD_LIMIT 2
124 T_HELPER_DECL(exc_resource_helper
, "exc_resource helper")
127 for (int i
= 0; i
< THREAD_LIMIT
; i
++) {
129 T_EXPECT_POSIX_SUCCESS(pthread_create(&tid
, NULL
, dummy_thread
, NULL
), "pthread_create");
137 check_exc_resource_threads_enabled()
141 size_t enabled_size
= sizeof(enabled
);
142 err
= sysctlbyname("kern.exc_resource_threads_enabled", &enabled
, &enabled_size
, NULL
, 0);
144 if (err
|| !enabled
) {
145 T_SKIP("EXC_RESOURCE RESOURCE_TYPE_THREADS not enabled on this system");
149 T_DECL(exc_resource_threads
, "Ensures that a process with a thread_limit set will receive an exc_resource when it crosses its thread limit",
151 T_META_CHECK_LEAKS(false))
153 pthread_t handle_thread
;
155 check_exc_resource_threads_enabled();
157 sync_sema
= dispatch_semaphore_create(0);
159 T_ASSERT_POSIX_ZERO(pthread_create(&handle_thread
, NULL
, exc_handler
, NULL
), "pthread_create");
160 dispatch_semaphore_wait(sync_sema
, DISPATCH_TIME_FOREVER
);
164 uint32_t path_size
= sizeof(path
);
166 T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path
, &path_size
), "_NSGetExecutablePath");
168 char *args
[] = { path
, "-n", "exc_resource_helper", NULL
};
170 posix_spawnattr_t attr
;
171 T_ASSERT_POSIX_ZERO(posix_spawnattr_init(&attr
), "posix_spawnattr_init");
173 T_EXPECT_POSIX_ZERO(posix_spawnattr_set_threadlimit_ext(&attr
, THREAD_LIMIT
), "posix_spawnattr_set_threadlimit_ext");
175 T_EXPECT_POSIX_ZERO(posix_spawn(&helper_pid
, args
[0], NULL
, &attr
, args
, NULL
), "posix_spawn");
177 T_ASSERT_POSIX_ZERO(posix_spawnattr_destroy(&attr
), "posix_spawnattr_destroy");
179 dispatch_semaphore_wait(sync_sema
, DISPATCH_TIME_FOREVER
);