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