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 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
24 static dispatch_semaphore_t sync_sema
;
27 catch_mach_exception_raise(mach_port_t exception_port
,
30 exception_type_t exception
,
31 mach_exception_data_t code
,
32 mach_msg_type_number_t code_count
)
34 #pragma unused(exception_port, thread, task, code, code_count)
36 pid_for_task(task
, &pid
);
37 T_ASSERT_EQ(exception
, EXC_CORPSE_NOTIFY
, "exception type");
38 T_ASSERT_POSIX_ZERO(kill(pid
, SIGKILL
), "kill");
39 dispatch_semaphore_signal(sync_sema
);
44 catch_mach_exception_raise_state(mach_port_t exception_port
,
45 exception_type_t exception
,
46 const mach_exception_data_t code
,
47 mach_msg_type_number_t code_count
,
49 const thread_state_t old_state
,
50 mach_msg_type_number_t old_state_count
,
51 thread_state_t new_state
,
52 mach_msg_type_number_t
* new_state_count
)
54 #pragma unused(exception_port, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
55 T_FAIL("Unsupported catch_mach_exception_raise_state");
56 return KERN_NOT_SUPPORTED
;
60 catch_mach_exception_raise_state_identity(mach_port_t exception_port
,
63 exception_type_t exception
,
64 mach_exception_data_t code
,
65 mach_msg_type_number_t code_count
,
67 thread_state_t old_state
,
68 mach_msg_type_number_t old_state_count
,
69 thread_state_t new_state
,
70 mach_msg_type_number_t
* new_state_count
)
72 #pragma unused(exception_port, thread, task, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
73 T_FAIL("Unsupported catch_mach_exception_raise_state_identity");
74 return KERN_NOT_SUPPORTED
;
79 * setup exception handling port for EXC_CORPSE_NOTIFY.
80 * runs mach_msg_server once for receiving exception messages from kernel.
83 exc_handler(void * arg
)
87 mach_port_t exception_port
;
89 kret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &exception_port
);
90 if (kret
!= KERN_SUCCESS
) {
91 T_FAIL("mach_port_allocate: %s (%d)", mach_error_string(kret
), kret
);
94 kret
= mach_port_insert_right(mach_task_self(), exception_port
, exception_port
, MACH_MSG_TYPE_MAKE_SEND
);
95 if (kret
!= KERN_SUCCESS
) {
96 T_FAIL("mach_port_insert_right: %s (%d)", mach_error_string(kret
), kret
);
99 kret
= task_set_exception_ports(mach_task_self(), EXC_MASK_CRASH
| EXC_MASK_CORPSE_NOTIFY
, exception_port
,
100 (exception_behavior_t
)(EXCEPTION_DEFAULT
| MACH_EXCEPTION_CODES
), 0);
101 if (kret
!= KERN_SUCCESS
) {
102 T_FAIL("task_set_exception_ports: %s (%d)", mach_error_string(kret
), kret
);
105 dispatch_semaphore_signal(sync_sema
);
107 kret
= mach_msg_server(mach_exc_server
, MACH_MSG_SIZE_RELIABLE
, exception_port
, 0);
108 if (kret
!= KERN_SUCCESS
) {
109 T_FAIL("mach_msg_server: %s (%d)", mach_error_string(kret
), kret
);
116 dummy_thread(void *arg
)
124 #define THREAD_LIMIT 2
126 T_HELPER_DECL(exc_resource_helper
, "exc_resource helper")
129 for (int i
= 0; i
< THREAD_LIMIT
; i
++) {
131 T_EXPECT_POSIX_SUCCESS(pthread_create(&tid
, NULL
, dummy_thread
, NULL
), "pthread_create");
139 check_exc_resource_threads_enabled()
143 size_t enabled_size
= sizeof(enabled
);
144 err
= sysctlbyname("kern.exc_resource_threads_enabled", &enabled
, &enabled_size
, NULL
, 0);
146 if (err
|| !enabled
) {
147 T_SKIP("EXC_RESOURCE RESOURCE_TYPE_THREADS not enabled on this system");
151 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",
153 T_META_CHECK_LEAKS(false))
155 pthread_t handle_thread
;
157 check_exc_resource_threads_enabled();
159 sync_sema
= dispatch_semaphore_create(0);
161 T_ASSERT_POSIX_ZERO(pthread_create(&handle_thread
, NULL
, exc_handler
, NULL
), "pthread_create");
162 dispatch_semaphore_wait(sync_sema
, DISPATCH_TIME_FOREVER
);
166 uint32_t path_size
= sizeof(path
);
168 T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path
, &path_size
), "_NSGetExecutablePath");
170 char *args
[] = { path
, "-n", "exc_resource_helper", NULL
};
172 posix_spawnattr_t attr
;
173 T_ASSERT_POSIX_ZERO(posix_spawnattr_init(&attr
), "posix_spawnattr_init");
175 T_EXPECT_POSIX_ZERO(posix_spawnattr_set_threadlimit_ext(&attr
, THREAD_LIMIT
), "posix_spawnattr_set_threadlimit_ext");
177 T_EXPECT_POSIX_ZERO(posix_spawn(&helper_pid
, args
[0], NULL
, &attr
, args
, NULL
), "posix_spawn");
179 T_ASSERT_POSIX_ZERO(posix_spawnattr_destroy(&attr
), "posix_spawnattr_destroy");
181 dispatch_semaphore_wait(sync_sema
, DISPATCH_TIME_FOREVER
);