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
);
91 kret
= mach_port_insert_right(mach_task_self(), exception_port
, exception_port
, MACH_MSG_TYPE_MAKE_SEND
);
92 if (kret
!= KERN_SUCCESS
)
93 T_FAIL("mach_port_insert_right: %s (%d)", mach_error_string(kret
), kret
);
95 kret
= task_set_exception_ports(mach_task_self(), EXC_MASK_CRASH
| EXC_MASK_CORPSE_NOTIFY
, exception_port
,
96 (exception_behavior_t
)(EXCEPTION_DEFAULT
| MACH_EXCEPTION_CODES
), 0);
97 if (kret
!= KERN_SUCCESS
)
98 T_FAIL("task_set_exception_ports: %s (%d)", mach_error_string(kret
), kret
);
100 dispatch_semaphore_signal(sync_sema
);
102 kret
= mach_msg_server(mach_exc_server
, MACH_MSG_SIZE_RELIABLE
, exception_port
, 0);
103 if (kret
!= KERN_SUCCESS
)
104 T_FAIL("mach_msg_server: %s (%d)", mach_error_string(kret
), kret
);
110 dummy_thread(void *arg
) {
117 #define THREAD_LIMIT 2
119 T_HELPER_DECL(exc_resource_helper
, "exc_resource helper")
122 for (int i
= 0; i
< THREAD_LIMIT
; i
++) {
124 T_EXPECT_POSIX_SUCCESS(pthread_create(&tid
, NULL
, dummy_thread
, NULL
), "pthread_create");
132 check_exc_resource_threads_enabled()
136 size_t enabled_size
= sizeof(enabled
);
137 err
= sysctlbyname("kern.exc_resource_threads_enabled", &enabled
, &enabled_size
, NULL
, 0);
140 T_SKIP("EXC_RESOURCE RESOURCE_TYPE_THREADS not enabled on this system");
144 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",
146 T_META_CHECK_LEAKS(false))
148 pthread_t handle_thread
;
150 check_exc_resource_threads_enabled();
152 sync_sema
= dispatch_semaphore_create(0);
154 T_ASSERT_POSIX_ZERO(pthread_create(&handle_thread
, NULL
, exc_handler
, NULL
), "pthread_create");
155 dispatch_semaphore_wait(sync_sema
, DISPATCH_TIME_FOREVER
);
159 uint32_t path_size
= sizeof(path
);
161 T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path
, &path_size
), "_NSGetExecutablePath");
163 char *args
[] = { path
, "-n", "exc_resource_helper", NULL
};
165 posix_spawnattr_t attr
;
166 T_ASSERT_POSIX_ZERO(posix_spawnattr_init(&attr
), "posix_spawnattr_init");
168 T_EXPECT_POSIX_ZERO(posix_spawnattr_set_threadlimit_ext(&attr
, THREAD_LIMIT
), "posix_spawnattr_set_threadlimit_ext");
170 T_EXPECT_POSIX_ZERO(posix_spawn(&helper_pid
, args
[0], NULL
, &attr
, args
, NULL
), "posix_spawn");
172 T_ASSERT_POSIX_ZERO(posix_spawnattr_destroy(&attr
), "posix_spawnattr_destroy");
174 dispatch_semaphore_wait(sync_sema
, DISPATCH_TIME_FOREVER
);