1*043036a2SApple OSS Distributions /*
2*043036a2SApple OSS Distributions * Copyright (c) 2024 Apple Inc. All rights reserved.
3*043036a2SApple OSS Distributions *
4*043036a2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*043036a2SApple OSS Distributions *
6*043036a2SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*043036a2SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*043036a2SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*043036a2SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*043036a2SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*043036a2SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*043036a2SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*043036a2SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*043036a2SApple OSS Distributions *
15*043036a2SApple OSS Distributions * Please obtain a copy of the License at
16*043036a2SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*043036a2SApple OSS Distributions *
18*043036a2SApple OSS Distributions * The Original Code and all software distributed under the License are
19*043036a2SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*043036a2SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*043036a2SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*043036a2SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*043036a2SApple OSS Distributions * Please see the License for the specific language governing rights and
24*043036a2SApple OSS Distributions * limitations under the License.
25*043036a2SApple OSS Distributions *
26*043036a2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*043036a2SApple OSS Distributions */
28*043036a2SApple OSS Distributions
29*043036a2SApple OSS Distributions #include <signal.h>
30*043036a2SApple OSS Distributions #include <spawn.h>
31*043036a2SApple OSS Distributions #include <stdlib.h>
32*043036a2SApple OSS Distributions #include <sys/sysctl.h>
33*043036a2SApple OSS Distributions #include <sys/ptrace.h>
34*043036a2SApple OSS Distributions #include <sys/types.h>
35*043036a2SApple OSS Distributions #include <mach/mach.h>
36*043036a2SApple OSS Distributions #include <excserver.h>
37*043036a2SApple OSS Distributions #include <sys/mman.h>
38*043036a2SApple OSS Distributions #include <kern/exc_resource.h>
39*043036a2SApple OSS Distributions #include <TargetConditionals.h>
40*043036a2SApple OSS Distributions #include <mach/vm_page_size.h>
41*043036a2SApple OSS Distributions #include <sys/spawn_internal.h>
42*043036a2SApple OSS Distributions #include <mach/mach_vm.h>
43*043036a2SApple OSS Distributions
44*043036a2SApple OSS Distributions #include <darwintest.h>
45*043036a2SApple OSS Distributions #include <dispatch/dispatch.h>
46*043036a2SApple OSS Distributions #include <mach-o/dyld.h>
47*043036a2SApple OSS Distributions
48*043036a2SApple OSS Distributions /* internal */
49*043036a2SApple OSS Distributions #include <spawn_private.h>
50*043036a2SApple OSS Distributions #include <sys/kern_memorystatus.h>
51*043036a2SApple OSS Distributions
52*043036a2SApple OSS Distributions #define TEST_MEMLIMIT_MB 10
53*043036a2SApple OSS Distributions #define SEM_TIMEOUT dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC)
54*043036a2SApple OSS Distributions #define OWNED_VMOBJECTS_SYSCTL "vm.get_owned_vmobjects"
55*043036a2SApple OSS Distributions
56*043036a2SApple OSS Distributions T_GLOBAL_META(
57*043036a2SApple OSS Distributions T_META_NAMESPACE("xnu.memorystatus"),
58*043036a2SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
59*043036a2SApple OSS Distributions T_META_OWNER("aaron_j_sonin"),
60*043036a2SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("VM"));
61*043036a2SApple OSS Distributions
62*043036a2SApple OSS Distributions /* Globals */
63*043036a2SApple OSS Distributions static dispatch_semaphore_t sync_sema;
64*043036a2SApple OSS Distributions static pid_t child_pid;
65*043036a2SApple OSS Distributions static bool caught_crash = false, caught_corpse = false;
66*043036a2SApple OSS Distributions mach_port_t exception_port;
67*043036a2SApple OSS Distributions
68*043036a2SApple OSS Distributions /* Exception */
69*043036a2SApple OSS Distributions kern_return_t
catch_mach_exception_raise_state(mach_port_t exception_port,exception_type_t exception,const mach_exception_data_t code,mach_msg_type_number_t code_count,int * flavor,const thread_state_t old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)70*043036a2SApple OSS Distributions catch_mach_exception_raise_state(mach_port_t exception_port,
71*043036a2SApple OSS Distributions exception_type_t exception,
72*043036a2SApple OSS Distributions const mach_exception_data_t code,
73*043036a2SApple OSS Distributions mach_msg_type_number_t code_count,
74*043036a2SApple OSS Distributions int * flavor,
75*043036a2SApple OSS Distributions const thread_state_t old_state,
76*043036a2SApple OSS Distributions mach_msg_type_number_t old_state_count,
77*043036a2SApple OSS Distributions thread_state_t new_state,
78*043036a2SApple OSS Distributions mach_msg_type_number_t * new_state_count)
79*043036a2SApple OSS Distributions {
80*043036a2SApple OSS Distributions #pragma unused(exception_port, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
81*043036a2SApple OSS Distributions T_FAIL("Unsupported catch_mach_exception_raise_state");
82*043036a2SApple OSS Distributions return KERN_NOT_SUPPORTED;
83*043036a2SApple OSS Distributions }
84*043036a2SApple OSS Distributions
85*043036a2SApple OSS Distributions kern_return_t
catch_mach_exception_raise_state_identity(mach_port_t exception_port,mach_port_t thread,mach_port_t task,exception_type_t exception,mach_exception_data_t code,mach_msg_type_number_t code_count,int * flavor,thread_state_t old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)86*043036a2SApple OSS Distributions catch_mach_exception_raise_state_identity(mach_port_t exception_port,
87*043036a2SApple OSS Distributions mach_port_t thread,
88*043036a2SApple OSS Distributions mach_port_t task,
89*043036a2SApple OSS Distributions exception_type_t exception,
90*043036a2SApple OSS Distributions mach_exception_data_t code,
91*043036a2SApple OSS Distributions mach_msg_type_number_t code_count,
92*043036a2SApple OSS Distributions int * flavor,
93*043036a2SApple OSS Distributions thread_state_t old_state,
94*043036a2SApple OSS Distributions mach_msg_type_number_t old_state_count,
95*043036a2SApple OSS Distributions thread_state_t new_state,
96*043036a2SApple OSS Distributions mach_msg_type_number_t * new_state_count)
97*043036a2SApple OSS Distributions {
98*043036a2SApple OSS Distributions #pragma unused(exception_port, exception, code, code_count, flavor, old_state, old_state_count, new_state, new_state_count)
99*043036a2SApple OSS Distributions T_FAIL("Unsupported catch_mach_exception_raise_state_identity");
100*043036a2SApple OSS Distributions return KERN_NOT_SUPPORTED;
101*043036a2SApple OSS Distributions }
102*043036a2SApple OSS Distributions
103*043036a2SApple OSS Distributions kern_return_t
catch_mach_exception_raise_state_identity_protected(mach_port_t exception_port,uint64_t thread_id,mach_port_t task_id_token,exception_type_t exception,mach_exception_data_t codes,mach_msg_type_number_t codeCnt,int * flavor,thread_state_t old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)104*043036a2SApple OSS Distributions catch_mach_exception_raise_state_identity_protected(
105*043036a2SApple OSS Distributions mach_port_t exception_port,
106*043036a2SApple OSS Distributions uint64_t thread_id,
107*043036a2SApple OSS Distributions mach_port_t task_id_token,
108*043036a2SApple OSS Distributions exception_type_t exception,
109*043036a2SApple OSS Distributions mach_exception_data_t codes,
110*043036a2SApple OSS Distributions mach_msg_type_number_t codeCnt,
111*043036a2SApple OSS Distributions int * flavor,
112*043036a2SApple OSS Distributions thread_state_t old_state,
113*043036a2SApple OSS Distributions mach_msg_type_number_t old_state_count,
114*043036a2SApple OSS Distributions thread_state_t new_state,
115*043036a2SApple OSS Distributions mach_msg_type_number_t * new_state_count)
116*043036a2SApple OSS Distributions {
117*043036a2SApple OSS Distributions #pragma unused(exception_port, thread_id, task_id_token, exception, codes, codeCnt, flavor, old_state, old_state_count, new_state, new_state_count)
118*043036a2SApple OSS Distributions T_FAIL("Unsupported catch_mach_exception_raise_state_identity");
119*043036a2SApple OSS Distributions return KERN_NOT_SUPPORTED;
120*043036a2SApple OSS Distributions }
121*043036a2SApple OSS Distributions
122*043036a2SApple OSS Distributions kern_return_t
catch_mach_exception_raise_identity_protected(mach_port_t exception_port,uint64_t thread_id,mach_port_t task_id_token,exception_type_t exception,mach_exception_data_t codes,mach_msg_type_number_t codeCnt)123*043036a2SApple OSS Distributions catch_mach_exception_raise_identity_protected(
124*043036a2SApple OSS Distributions mach_port_t exception_port,
125*043036a2SApple OSS Distributions uint64_t thread_id,
126*043036a2SApple OSS Distributions mach_port_t task_id_token,
127*043036a2SApple OSS Distributions exception_type_t exception,
128*043036a2SApple OSS Distributions mach_exception_data_t codes,
129*043036a2SApple OSS Distributions mach_msg_type_number_t codeCnt)
130*043036a2SApple OSS Distributions {
131*043036a2SApple OSS Distributions #pragma unused(exception_port, thread_id, task_id_token, exception, codes, codeCnt)
132*043036a2SApple OSS Distributions T_FAIL("Unsupported catch_mach_exception_raise_state_identity");
133*043036a2SApple OSS Distributions return KERN_NOT_SUPPORTED;
134*043036a2SApple OSS Distributions }
135*043036a2SApple OSS Distributions
136*043036a2SApple OSS Distributions void
verify_owned_vmobjects(task_t task)137*043036a2SApple OSS Distributions verify_owned_vmobjects(task_t task)
138*043036a2SApple OSS Distributions {
139*043036a2SApple OSS Distributions int ret;
140*043036a2SApple OSS Distributions size_t owned_vmobjects_len;
141*043036a2SApple OSS Distributions
142*043036a2SApple OSS Distributions ret = sysctlbyname(OWNED_VMOBJECTS_SYSCTL, NULL, &owned_vmobjects_len, &task, sizeof(task));
143*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl " OWNED_VMOBJECTS_SYSCTL);
144*043036a2SApple OSS Distributions T_EXPECT_GT((int) owned_vmobjects_len, 0, "owned vmobjects list is populated on %s", (task == mach_task_self()) ? "self" : "corpse");
145*043036a2SApple OSS Distributions }
146*043036a2SApple OSS Distributions
147*043036a2SApple OSS Distributions kern_return_t
catch_mach_exception_raise(mach_port_t exception_port,mach_port_t thread,mach_port_t task,exception_type_t exception,mach_exception_data_t code,mach_msg_type_number_t code_count)148*043036a2SApple OSS Distributions catch_mach_exception_raise(mach_port_t exception_port,
149*043036a2SApple OSS Distributions mach_port_t thread,
150*043036a2SApple OSS Distributions mach_port_t task,
151*043036a2SApple OSS Distributions exception_type_t exception,
152*043036a2SApple OSS Distributions mach_exception_data_t code,
153*043036a2SApple OSS Distributions mach_msg_type_number_t code_count)
154*043036a2SApple OSS Distributions {
155*043036a2SApple OSS Distributions #pragma unused(thread, task, code, code_count)
156*043036a2SApple OSS Distributions T_QUIET; T_EXPECT_TRUE((exception == EXC_CRASH) || (exception == EXC_CORPSE_NOTIFY), "catch_mach_exception_raise() catches EXC_CRASH or EXC_CORPSE_NOTIFY");
157*043036a2SApple OSS Distributions if (exception == EXC_CRASH) {
158*043036a2SApple OSS Distributions caught_crash = true;
159*043036a2SApple OSS Distributions return KERN_SUCCESS;
160*043036a2SApple OSS Distributions } else if (exception == EXC_CORPSE_NOTIFY) {
161*043036a2SApple OSS Distributions caught_corpse = true;
162*043036a2SApple OSS Distributions verify_owned_vmobjects(task);
163*043036a2SApple OSS Distributions dispatch_semaphore_signal(sync_sema);
164*043036a2SApple OSS Distributions return KERN_SUCCESS;
165*043036a2SApple OSS Distributions }
166*043036a2SApple OSS Distributions return KERN_NOT_SUPPORTED;
167*043036a2SApple OSS Distributions }
168*043036a2SApple OSS Distributions
169*043036a2SApple OSS Distributions /*
170*043036a2SApple OSS Distributions * Background process that will allocate enough memory to push
171*043036a2SApple OSS Distributions * itself over the threshold, hopefully triggering EXC_RESOURCE.
172*043036a2SApple OSS Distributions */
173*043036a2SApple OSS Distributions T_HELPER_DECL(i_eat_memory_for_breakfast, "") {
174*043036a2SApple OSS Distributions int ret, j, num_pages = 0;
175*043036a2SApple OSS Distributions unsigned char *buf;
176*043036a2SApple OSS Distributions
177*043036a2SApple OSS Distributions if (argc == 1) {
178*043036a2SApple OSS Distributions num_pages = atoi(argv[0]);
179*043036a2SApple OSS Distributions } else {
180*043036a2SApple OSS Distributions T_FAIL("No arguments passed to memory eater");
181*043036a2SApple OSS Distributions }
182*043036a2SApple OSS Distributions
183*043036a2SApple OSS Distributions /* Allocate a purgeable buffer that will show up in owned vmobjects */
184*043036a2SApple OSS Distributions mach_vm_address_t addr = 0;
185*043036a2SApple OSS Distributions ret = mach_vm_allocate(mach_task_self(), &addr, vm_page_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
186*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "allocate purgeable buffer");
187*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_NE((int) addr, 0, "purgeable buffer not null");
188*043036a2SApple OSS Distributions verify_owned_vmobjects(mach_task_self());
189*043036a2SApple OSS Distributions
190*043036a2SApple OSS Distributions /* Allocate and touch all our pages */
191*043036a2SApple OSS Distributions T_LOG("Allocating %d pages...", num_pages);
192*043036a2SApple OSS Distributions buf = mmap(NULL, vm_page_size * num_pages, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
193*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(buf, "mmap");
194*043036a2SApple OSS Distributions for (j = 0; j < num_pages; j++) {
195*043036a2SApple OSS Distributions ((volatile unsigned char *)buf)[j * vm_page_size] = 1;
196*043036a2SApple OSS Distributions }
197*043036a2SApple OSS Distributions
198*043036a2SApple OSS Distributions exit(0);
199*043036a2SApple OSS Distributions }
200*043036a2SApple OSS Distributions
201*043036a2SApple OSS Distributions static void
kill_child(void)202*043036a2SApple OSS Distributions kill_child(void)
203*043036a2SApple OSS Distributions {
204*043036a2SApple OSS Distributions int ret = kill(child_pid, SIGKILL);
205*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kill");
206*043036a2SApple OSS Distributions }
207*043036a2SApple OSS Distributions
208*043036a2SApple OSS Distributions static pid_t
launch_child(int num_pages)209*043036a2SApple OSS Distributions launch_child(int num_pages)
210*043036a2SApple OSS Distributions {
211*043036a2SApple OSS Distributions extern char **environ;
212*043036a2SApple OSS Distributions int ret;
213*043036a2SApple OSS Distributions char testpath[PATH_MAX];
214*043036a2SApple OSS Distributions posix_spawnattr_t spawn_attrs;
215*043036a2SApple OSS Distributions
216*043036a2SApple OSS Distributions uint32_t testpath_buf_size = PATH_MAX;
217*043036a2SApple OSS Distributions char num_pages_str[32] = {0};
218*043036a2SApple OSS Distributions char *argv[5] = {testpath, "-n", "i_eat_memory_for_breakfast", num_pages_str, NULL};
219*043036a2SApple OSS Distributions
220*043036a2SApple OSS Distributions T_LOG("Spawning child process...");
221*043036a2SApple OSS Distributions
222*043036a2SApple OSS Distributions /* Fork so we can keep the exception port. */
223*043036a2SApple OSS Distributions if ((child_pid = fork()) == 0) {
224*043036a2SApple OSS Distributions ret = posix_spawnattr_init(&spawn_attrs);
225*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_init");
226*043036a2SApple OSS Distributions ret = posix_spawnattr_setjetsam_ext(&spawn_attrs, POSIX_SPAWN_JETSAM_MEMLIMIT_FATAL, JETSAM_PRIORITY_FOREGROUND, TEST_MEMLIMIT_MB, TEST_MEMLIMIT_MB);
227*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_setjetsam_ext");
228*043036a2SApple OSS Distributions ret = posix_spawnattr_setflags(&spawn_attrs, POSIX_SPAWN_SETEXEC);
229*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_setflags");
230*043036a2SApple OSS Distributions ret = snprintf(num_pages_str, sizeof(num_pages_str), "%d", num_pages);
231*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_LE((size_t) ret, sizeof(num_pages_str), "Don't allocate too many pages.");
232*043036a2SApple OSS Distributions ret = _NSGetExecutablePath(testpath, &testpath_buf_size);
233*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "_NSGetExecutablePath");
234*043036a2SApple OSS Distributions ret = posix_spawn(&child_pid, argv[0], NULL, &spawn_attrs, argv, environ);
235*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "posix_spawn");
236*043036a2SApple OSS Distributions }
237*043036a2SApple OSS Distributions
238*043036a2SApple OSS Distributions T_ATEND(kill_child);
239*043036a2SApple OSS Distributions
240*043036a2SApple OSS Distributions return child_pid;
241*043036a2SApple OSS Distributions }
242*043036a2SApple OSS Distributions
243*043036a2SApple OSS Distributions void*
exc_thread(void * arg)244*043036a2SApple OSS Distributions exc_thread(void *arg)
245*043036a2SApple OSS Distributions {
246*043036a2SApple OSS Distributions #pragma unused(arg)
247*043036a2SApple OSS Distributions kern_return_t kr;
248*043036a2SApple OSS Distributions
249*043036a2SApple OSS Distributions while (1) {
250*043036a2SApple OSS Distributions kr = mach_msg_server(mach_exc_server, MACH_MSG_SIZE_RELIABLE, exception_port, 0);
251*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_msg_server");
252*043036a2SApple OSS Distributions }
253*043036a2SApple OSS Distributions }
254*043036a2SApple OSS Distributions
255*043036a2SApple OSS Distributions T_DECL(corpse_owned_vmobjects, "vm.get_owned_vmobjects sysctl on corpses",
256*043036a2SApple OSS Distributions T_META_ASROOT(true),
257*043036a2SApple OSS Distributions T_META_BOOTARGS_SET("memstat_no_task_limit_increase=1"),
258*043036a2SApple OSS Distributions T_META_TAG_VM_PREFERRED
259*043036a2SApple OSS Distributions )
260*043036a2SApple OSS Distributions {
261*043036a2SApple OSS Distributions int ret;
262*043036a2SApple OSS Distributions pthread_t handle_thread;
263*043036a2SApple OSS Distributions task_t task;
264*043036a2SApple OSS Distributions
265*043036a2SApple OSS Distributions T_SETUPBEGIN;
266*043036a2SApple OSS Distributions
267*043036a2SApple OSS Distributions sync_sema = dispatch_semaphore_create(0);
268*043036a2SApple OSS Distributions
269*043036a2SApple OSS Distributions task = mach_task_self();
270*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_NE(task, MACH_PORT_NULL, "mach_task_self");
271*043036a2SApple OSS Distributions
272*043036a2SApple OSS Distributions /* Allocate a port for receiving EXC_CRASH and EXC_CORPSE_NOTIFY */
273*043036a2SApple OSS Distributions ret = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exception_port);
274*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "mach_port_allocate");
275*043036a2SApple OSS Distributions ret = mach_port_insert_right(task, exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
276*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "mach_port_insert_right");
277*043036a2SApple OSS Distributions ret = task_set_exception_ports(task, EXC_MASK_CRASH | EXC_MASK_CORPSE_NOTIFY, exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, 0);
278*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "task_set_exception_ports");
279*043036a2SApple OSS Distributions
280*043036a2SApple OSS Distributions T_SETUPEND;
281*043036a2SApple OSS Distributions
282*043036a2SApple OSS Distributions /* Spawn exception handling thread */
283*043036a2SApple OSS Distributions ret = pthread_create(&handle_thread, NULL, exc_thread, 0);
284*043036a2SApple OSS Distributions
285*043036a2SApple OSS Distributions /* Spawn child to eat memory and trigger EXC_RESOURCE */
286*043036a2SApple OSS Distributions launch_child((TEST_MEMLIMIT_MB * (1 << 20)) / vm_page_size);
287*043036a2SApple OSS Distributions
288*043036a2SApple OSS Distributions /* We should receive an exception */
289*043036a2SApple OSS Distributions dispatch_semaphore_wait(sync_sema, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC));
290*043036a2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(caught_crash, true, "Caught EXC_CRASH");
291*043036a2SApple OSS Distributions T_QUIET; T_EXPECT_EQ(caught_corpse, true, "Caught EXC_CORPSE_NOTIFY");
292*043036a2SApple OSS Distributions }
293