xref: /xnu-12377.61.12/tests/try_read_write_test.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1*4d495c6eSApple OSS Distributions /*
2*4d495c6eSApple OSS Distributions  * Copyright (c) 2024 Apple Inc. All rights reserved.
3*4d495c6eSApple OSS Distributions  *
4*4d495c6eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4d495c6eSApple OSS Distributions  *
6*4d495c6eSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4d495c6eSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4d495c6eSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4d495c6eSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4d495c6eSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4d495c6eSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4d495c6eSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4d495c6eSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4d495c6eSApple OSS Distributions  *
15*4d495c6eSApple OSS Distributions  * Please obtain a copy of the License at
16*4d495c6eSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4d495c6eSApple OSS Distributions  *
18*4d495c6eSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4d495c6eSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4d495c6eSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4d495c6eSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4d495c6eSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4d495c6eSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4d495c6eSApple OSS Distributions  * limitations under the License.
25*4d495c6eSApple OSS Distributions  *
26*4d495c6eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4d495c6eSApple OSS Distributions  */
28*4d495c6eSApple OSS Distributions 
29*4d495c6eSApple OSS Distributions /*
30*4d495c6eSApple OSS Distributions  * try_read_write_test.c
31*4d495c6eSApple OSS Distributions  *
32*4d495c6eSApple OSS Distributions  * Test the testing helper functions in try_read_write.h.
33*4d495c6eSApple OSS Distributions  */
34*4d495c6eSApple OSS Distributions 
35*4d495c6eSApple OSS Distributions #include <stdlib.h>
36*4d495c6eSApple OSS Distributions #include <stdint.h>
37*4d495c6eSApple OSS Distributions #include <stdbool.h>
38*4d495c6eSApple OSS Distributions #include <darwintest.h>
39*4d495c6eSApple OSS Distributions #include <mach/mach.h>
40*4d495c6eSApple OSS Distributions #include <mach/mach_vm.h>
41*4d495c6eSApple OSS Distributions #include <ptrauth.h>
42*4d495c6eSApple OSS Distributions 
43*4d495c6eSApple OSS Distributions #include "try_read_write.h"
44*4d495c6eSApple OSS Distributions 
45*4d495c6eSApple OSS Distributions T_GLOBAL_META(
46*4d495c6eSApple OSS Distributions 	T_META_NAMESPACE("xnu"),
47*4d495c6eSApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
48*4d495c6eSApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("vm"),
49*4d495c6eSApple OSS Distributions 	T_META_RUN_CONCURRENTLY(true),
50*4d495c6eSApple OSS Distributions 	T_META_ALL_VALID_ARCHS(true)
51*4d495c6eSApple OSS Distributions 	);
52*4d495c6eSApple OSS Distributions 
53*4d495c6eSApple OSS Distributions #define MAYBE_QUIET(quiet) \
54*4d495c6eSApple OSS Distributions 	do {                                    \
55*4d495c6eSApple OSS Distributions 	        if (quiet) {                    \
56*4d495c6eSApple OSS Distributions 	                T_QUIET;                \
57*4d495c6eSApple OSS Distributions 	        }                               \
58*4d495c6eSApple OSS Distributions 	} while (0)
59*4d495c6eSApple OSS Distributions 
60*4d495c6eSApple OSS Distributions static void
test_try_read_byte_maybe_quietly(mach_vm_address_t addr,uint8_t expected_byte,kern_return_t expected_error,bool quiet,const char * message)61*4d495c6eSApple OSS Distributions test_try_read_byte_maybe_quietly(
62*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr,
63*4d495c6eSApple OSS Distributions 	uint8_t expected_byte,
64*4d495c6eSApple OSS Distributions 	kern_return_t expected_error,
65*4d495c6eSApple OSS Distributions 	bool quiet,
66*4d495c6eSApple OSS Distributions 	const char *message)
67*4d495c6eSApple OSS Distributions {
68*4d495c6eSApple OSS Distributions 	bool expected_result = (expected_error == 0);
69*4d495c6eSApple OSS Distributions 	bool actual_result;
70*4d495c6eSApple OSS Distributions 	uint8_t actual_byte;
71*4d495c6eSApple OSS Distributions 	kern_return_t actual_error;
72*4d495c6eSApple OSS Distributions 
73*4d495c6eSApple OSS Distributions 	actual_result = try_read_byte(addr, &actual_byte, &actual_error);
74*4d495c6eSApple OSS Distributions 
75*4d495c6eSApple OSS Distributions 	MAYBE_QUIET(quiet); T_EXPECT_EQ(expected_result, actual_result, "%s: try_read_byte return value", message);
76*4d495c6eSApple OSS Distributions 	MAYBE_QUIET(quiet); T_EXPECT_EQ(expected_error, actual_error, "%s: try_read_byte error code", message);
77*4d495c6eSApple OSS Distributions 	if (expected_error == 0 && actual_error == 0) {
78*4d495c6eSApple OSS Distributions 		MAYBE_QUIET(quiet); T_EXPECT_EQ(expected_byte, actual_byte, "%s: try_read_byte value read", message);
79*4d495c6eSApple OSS Distributions 	}
80*4d495c6eSApple OSS Distributions }
81*4d495c6eSApple OSS Distributions 
82*4d495c6eSApple OSS Distributions static void
test_try_read_byte(mach_vm_address_t addr,uint8_t expected_byte,kern_return_t expected_error,const char * message)83*4d495c6eSApple OSS Distributions test_try_read_byte(
84*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr,
85*4d495c6eSApple OSS Distributions 	uint8_t expected_byte,
86*4d495c6eSApple OSS Distributions 	kern_return_t expected_error,
87*4d495c6eSApple OSS Distributions 	const char *message)
88*4d495c6eSApple OSS Distributions {
89*4d495c6eSApple OSS Distributions 	test_try_read_byte_maybe_quietly(addr, expected_byte, expected_error, false /* quiet */, message);
90*4d495c6eSApple OSS Distributions }
91*4d495c6eSApple OSS Distributions 
92*4d495c6eSApple OSS Distributions static void
test_try_read_byte_quietly(mach_vm_address_t addr,uint8_t expected_byte,kern_return_t expected_error,const char * message)93*4d495c6eSApple OSS Distributions test_try_read_byte_quietly(
94*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr,
95*4d495c6eSApple OSS Distributions 	uint8_t expected_byte,
96*4d495c6eSApple OSS Distributions 	kern_return_t expected_error,
97*4d495c6eSApple OSS Distributions 	const char *message)
98*4d495c6eSApple OSS Distributions {
99*4d495c6eSApple OSS Distributions 	test_try_read_byte_maybe_quietly(addr, expected_byte, expected_error, true /* quiet */, message);
100*4d495c6eSApple OSS Distributions }
101*4d495c6eSApple OSS Distributions 
102*4d495c6eSApple OSS Distributions static void
test_try_write_byte_maybe_quietly(mach_vm_address_t addr,uint8_t expected_byte,kern_return_t expected_error,bool quiet,const char * message)103*4d495c6eSApple OSS Distributions test_try_write_byte_maybe_quietly(
104*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr,
105*4d495c6eSApple OSS Distributions 	uint8_t expected_byte,
106*4d495c6eSApple OSS Distributions 	kern_return_t expected_error,
107*4d495c6eSApple OSS Distributions 	bool quiet,
108*4d495c6eSApple OSS Distributions 	const char *message)
109*4d495c6eSApple OSS Distributions {
110*4d495c6eSApple OSS Distributions 	bool expected_result = (expected_error == 0);
111*4d495c6eSApple OSS Distributions 	bool actual_result;
112*4d495c6eSApple OSS Distributions 	uint8_t actual_byte;
113*4d495c6eSApple OSS Distributions 	kern_return_t actual_error;
114*4d495c6eSApple OSS Distributions 
115*4d495c6eSApple OSS Distributions 	actual_result = try_write_byte(addr, expected_byte, &actual_error);
116*4d495c6eSApple OSS Distributions 
117*4d495c6eSApple OSS Distributions 	MAYBE_QUIET(quiet); T_EXPECT_EQ(expected_result, actual_result, "%s: try_write_byte return value", message);
118*4d495c6eSApple OSS Distributions 	MAYBE_QUIET(quiet); T_EXPECT_EQ(expected_error, actual_error, "%s: try_write_byte error code", message);
119*4d495c6eSApple OSS Distributions 	if (expected_error == 0 && actual_error == 0) {
120*4d495c6eSApple OSS Distributions 		actual_byte = *(volatile uint8_t *)addr;
121*4d495c6eSApple OSS Distributions 		MAYBE_QUIET(quiet); T_EXPECT_EQ(expected_byte, actual_byte, "%s: try_write_byte value written", message);
122*4d495c6eSApple OSS Distributions 	}
123*4d495c6eSApple OSS Distributions }
124*4d495c6eSApple OSS Distributions 
125*4d495c6eSApple OSS Distributions static void
test_try_write_byte(mach_vm_address_t addr,uint8_t expected_byte,kern_return_t expected_error,const char * message)126*4d495c6eSApple OSS Distributions test_try_write_byte(
127*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr,
128*4d495c6eSApple OSS Distributions 	uint8_t expected_byte,
129*4d495c6eSApple OSS Distributions 	kern_return_t expected_error,
130*4d495c6eSApple OSS Distributions 	const char *message)
131*4d495c6eSApple OSS Distributions {
132*4d495c6eSApple OSS Distributions 	test_try_write_byte_maybe_quietly(addr, expected_byte, expected_error, false /* quiet */, message);
133*4d495c6eSApple OSS Distributions }
134*4d495c6eSApple OSS Distributions 
135*4d495c6eSApple OSS Distributions static void
test_try_write_byte_quietly(mach_vm_address_t addr,uint8_t expected_byte,kern_return_t expected_error,const char * message)136*4d495c6eSApple OSS Distributions test_try_write_byte_quietly(
137*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr,
138*4d495c6eSApple OSS Distributions 	uint8_t expected_byte,
139*4d495c6eSApple OSS Distributions 	kern_return_t expected_error,
140*4d495c6eSApple OSS Distributions 	const char *message)
141*4d495c6eSApple OSS Distributions {
142*4d495c6eSApple OSS Distributions 	test_try_write_byte_maybe_quietly(addr, expected_byte, expected_error, true /* quiet */, message);
143*4d495c6eSApple OSS Distributions }
144*4d495c6eSApple OSS Distributions 
145*4d495c6eSApple OSS Distributions static mach_vm_address_t
allocate_page_with_prot(vm_prot_t prot)146*4d495c6eSApple OSS Distributions allocate_page_with_prot(vm_prot_t prot)
147*4d495c6eSApple OSS Distributions {
148*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr;
149*4d495c6eSApple OSS Distributions 	kern_return_t kr;
150*4d495c6eSApple OSS Distributions 
151*4d495c6eSApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr, PAGE_SIZE, VM_FLAGS_ANYWHERE);
152*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate");
153*4d495c6eSApple OSS Distributions 	kr = mach_vm_protect(mach_task_self(), addr, PAGE_SIZE, false /* set max */, prot);
154*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_protect");
155*4d495c6eSApple OSS Distributions 	return addr;
156*4d495c6eSApple OSS Distributions }
157*4d495c6eSApple OSS Distributions 
158*4d495c6eSApple OSS Distributions static void
deallocate_page(mach_vm_address_t addr)159*4d495c6eSApple OSS Distributions deallocate_page(mach_vm_address_t addr)
160*4d495c6eSApple OSS Distributions {
161*4d495c6eSApple OSS Distributions 	kern_return_t kr = mach_vm_deallocate(mach_task_self(), addr, PAGE_SIZE);
162*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate");
163*4d495c6eSApple OSS Distributions }
164*4d495c6eSApple OSS Distributions 
165*4d495c6eSApple OSS Distributions /*
166*4d495c6eSApple OSS Distributions  * Generate some r-x memory with a known value.
167*4d495c6eSApple OSS Distributions  */
168*4d495c6eSApple OSS Distributions static void __attribute__((naked))
instruction_byte_ff(void)169*4d495c6eSApple OSS Distributions instruction_byte_ff(void)
170*4d495c6eSApple OSS Distributions {
171*4d495c6eSApple OSS Distributions 	asm(".quad 0xffffffff");
172*4d495c6eSApple OSS Distributions }
173*4d495c6eSApple OSS Distributions 
174*4d495c6eSApple OSS Distributions T_DECL(try_read_write_test,
175*4d495c6eSApple OSS Distributions     "test the test helper functions try_read_byte and try_write_byte")
176*4d495c6eSApple OSS Distributions {
177*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr;
178*4d495c6eSApple OSS Distributions 
179*4d495c6eSApple OSS Distributions 	/* read and write an unmapped address */
180*4d495c6eSApple OSS Distributions 	test_try_read_byte(0, 0, KERN_INVALID_ADDRESS, "read unmapped address");
181*4d495c6eSApple OSS Distributions 	test_try_write_byte(0, 0, KERN_INVALID_ADDRESS, "write unmapped address");
182*4d495c6eSApple OSS Distributions 
183*4d495c6eSApple OSS Distributions 	/* read and write --- */
184*4d495c6eSApple OSS Distributions 	addr = allocate_page_with_prot(VM_PROT_NONE);
185*4d495c6eSApple OSS Distributions 	test_try_read_byte(addr, 0, KERN_PROTECTION_FAILURE, "read prot ---");
186*4d495c6eSApple OSS Distributions 	test_try_write_byte(addr, 1, KERN_PROTECTION_FAILURE, "write prot ---");
187*4d495c6eSApple OSS Distributions 	deallocate_page(addr);
188*4d495c6eSApple OSS Distributions 
189*4d495c6eSApple OSS Distributions 	/* read and write r-- */
190*4d495c6eSApple OSS Distributions 	addr = allocate_page_with_prot(VM_PROT_READ);
191*4d495c6eSApple OSS Distributions 	test_try_read_byte(addr, 0, KERN_SUCCESS, "read prot r--");
192*4d495c6eSApple OSS Distributions 	test_try_write_byte(addr, 1, KERN_PROTECTION_FAILURE, "write prot r--");
193*4d495c6eSApple OSS Distributions 	deallocate_page(addr);
194*4d495c6eSApple OSS Distributions 
195*4d495c6eSApple OSS Distributions 	/* read and write -w- */
196*4d495c6eSApple OSS Distributions 	addr = allocate_page_with_prot(VM_PROT_WRITE);
197*4d495c6eSApple OSS Distributions 	test_try_read_byte(addr, 0, KERN_PROTECTION_FAILURE, "read prot -w-");
198*4d495c6eSApple OSS Distributions 	test_try_write_byte(addr, 1, KERN_PROTECTION_FAILURE, "write prot -w-");
199*4d495c6eSApple OSS Distributions 	deallocate_page(addr);
200*4d495c6eSApple OSS Distributions 
201*4d495c6eSApple OSS Distributions 	/* read and write rw- */
202*4d495c6eSApple OSS Distributions 	addr = allocate_page_with_prot(VM_PROT_READ | VM_PROT_WRITE);
203*4d495c6eSApple OSS Distributions 	*(uint8_t *)addr = 1;
204*4d495c6eSApple OSS Distributions 	test_try_read_byte(addr, 1, KERN_SUCCESS, "read prot rw-");
205*4d495c6eSApple OSS Distributions 	test_try_write_byte(addr, 2, KERN_SUCCESS, "write prot rw-");
206*4d495c6eSApple OSS Distributions 	test_try_read_byte(addr, 2, KERN_SUCCESS, "read prot rw- again");
207*4d495c6eSApple OSS Distributions 	deallocate_page(addr);
208*4d495c6eSApple OSS Distributions 
209*4d495c6eSApple OSS Distributions 	/* read and write r-x */
210*4d495c6eSApple OSS Distributions 	addr = (mach_vm_address_t)ptrauth_strip(&instruction_byte_ff, ptrauth_key_function_pointer);
211*4d495c6eSApple OSS Distributions 	test_try_read_byte(addr, 0xff, KERN_SUCCESS, "read prot r-x");
212*4d495c6eSApple OSS Distributions 	test_try_write_byte(addr, 1, KERN_PROTECTION_FAILURE, "write prot r-x");
213*4d495c6eSApple OSS Distributions }
214*4d495c6eSApple OSS Distributions 
215*4d495c6eSApple OSS Distributions 
216*4d495c6eSApple OSS Distributions /* this test provokes THREAD_COUNT * REP_COUNT * PAGE_SIZE exceptions */
217*4d495c6eSApple OSS Distributions #define THREAD_COUNT 10
218*4d495c6eSApple OSS Distributions #define REP_COUNT 5
219*4d495c6eSApple OSS Distributions 
220*4d495c6eSApple OSS Distributions struct test_alloc {
221*4d495c6eSApple OSS Distributions 	mach_vm_address_t addr;
222*4d495c6eSApple OSS Distributions 	vm_prot_t prot;
223*4d495c6eSApple OSS Distributions 	kern_return_t expected_read_error;
224*4d495c6eSApple OSS Distributions 	kern_return_t expected_write_error;
225*4d495c6eSApple OSS Distributions };
226*4d495c6eSApple OSS Distributions 
227*4d495c6eSApple OSS Distributions static struct test_alloc
allocate_page_with_random_prot(void)228*4d495c6eSApple OSS Distributions allocate_page_with_random_prot(void)
229*4d495c6eSApple OSS Distributions {
230*4d495c6eSApple OSS Distributions 	struct test_alloc result;
231*4d495c6eSApple OSS Distributions 
232*4d495c6eSApple OSS Distributions 	switch (random() % 4) {
233*4d495c6eSApple OSS Distributions 	case 0:
234*4d495c6eSApple OSS Distributions 		result.prot = VM_PROT_NONE;
235*4d495c6eSApple OSS Distributions 		result.expected_read_error  = KERN_PROTECTION_FAILURE;
236*4d495c6eSApple OSS Distributions 		result.expected_write_error = KERN_PROTECTION_FAILURE;
237*4d495c6eSApple OSS Distributions 		break;
238*4d495c6eSApple OSS Distributions 	case 1:
239*4d495c6eSApple OSS Distributions 		result.prot = VM_PROT_READ;
240*4d495c6eSApple OSS Distributions 		result.expected_read_error  = KERN_SUCCESS;
241*4d495c6eSApple OSS Distributions 		result.expected_write_error = KERN_PROTECTION_FAILURE;
242*4d495c6eSApple OSS Distributions 		break;
243*4d495c6eSApple OSS Distributions 	case 2:
244*4d495c6eSApple OSS Distributions 		result.prot = VM_PROT_WRITE;
245*4d495c6eSApple OSS Distributions 		result.expected_read_error  = KERN_PROTECTION_FAILURE;
246*4d495c6eSApple OSS Distributions 		result.expected_write_error = KERN_PROTECTION_FAILURE;
247*4d495c6eSApple OSS Distributions 		break;
248*4d495c6eSApple OSS Distributions 	case 3:
249*4d495c6eSApple OSS Distributions 		result.prot = VM_PROT_READ | VM_PROT_WRITE;
250*4d495c6eSApple OSS Distributions 		result.expected_read_error  = KERN_SUCCESS;
251*4d495c6eSApple OSS Distributions 		result.expected_write_error = KERN_SUCCESS;
252*4d495c6eSApple OSS Distributions 		break;
253*4d495c6eSApple OSS Distributions 	}
254*4d495c6eSApple OSS Distributions 
255*4d495c6eSApple OSS Distributions 	result.addr = allocate_page_with_prot(result.prot);
256*4d495c6eSApple OSS Distributions 	return result;
257*4d495c6eSApple OSS Distributions }
258*4d495c6eSApple OSS Distributions 
259*4d495c6eSApple OSS Distributions static void *
multithreaded_test(void * arg)260*4d495c6eSApple OSS Distributions multithreaded_test(void *arg)
261*4d495c6eSApple OSS Distributions {
262*4d495c6eSApple OSS Distributions 	struct test_alloc alloc = *(struct test_alloc *)arg;
263*4d495c6eSApple OSS Distributions 
264*4d495c6eSApple OSS Distributions 	/* Read and write a lot from our page. */
265*4d495c6eSApple OSS Distributions 	for (int reps = 0; reps < REP_COUNT; reps++) {
266*4d495c6eSApple OSS Distributions 		for (int offset = 0; offset < PAGE_SIZE; offset++) {
267*4d495c6eSApple OSS Distributions 			test_try_read_byte_quietly(alloc.addr + offset, 0, alloc.expected_read_error, "thread read");
268*4d495c6eSApple OSS Distributions 			test_try_write_byte_quietly(alloc.addr + offset, 0, alloc.expected_write_error, "thread write");
269*4d495c6eSApple OSS Distributions 		}
270*4d495c6eSApple OSS Distributions 	}
271*4d495c6eSApple OSS Distributions 
272*4d495c6eSApple OSS Distributions 	return NULL;
273*4d495c6eSApple OSS Distributions }
274*4d495c6eSApple OSS Distributions 
275*4d495c6eSApple OSS Distributions T_DECL(try_read_write_test_multithreaded,
276*4d495c6eSApple OSS Distributions     "test try_read_byte and try_write_byte from multiple threads")
277*4d495c6eSApple OSS Distributions {
278*4d495c6eSApple OSS Distributions 	verbose_exc_helper = false;
279*4d495c6eSApple OSS Distributions 
280*4d495c6eSApple OSS Distributions 	pthread_t threads[THREAD_COUNT];
281*4d495c6eSApple OSS Distributions 	struct test_alloc allocs[THREAD_COUNT];
282*4d495c6eSApple OSS Distributions 
283*4d495c6eSApple OSS Distributions 	/* each thread gets a page with a random prot to read and write on */
284*4d495c6eSApple OSS Distributions 
285*4d495c6eSApple OSS Distributions 	for (int i = 0; i < THREAD_COUNT; i++) {
286*4d495c6eSApple OSS Distributions 		allocs[i] = allocate_page_with_random_prot();
287*4d495c6eSApple OSS Distributions 	}
288*4d495c6eSApple OSS Distributions 
289*4d495c6eSApple OSS Distributions 	T_LOG("running %d threads each %d times", THREAD_COUNT, REP_COUNT);
290*4d495c6eSApple OSS Distributions 
291*4d495c6eSApple OSS Distributions 	for (int i = 0; i < THREAD_COUNT; i++) {
292*4d495c6eSApple OSS Distributions 		pthread_create(&threads[i], NULL, multithreaded_test, &allocs[i]);
293*4d495c6eSApple OSS Distributions 	}
294*4d495c6eSApple OSS Distributions 
295*4d495c6eSApple OSS Distributions 	for (int i = 0; i < THREAD_COUNT; i++) {
296*4d495c6eSApple OSS Distributions 		pthread_join(threads[i], NULL);
297*4d495c6eSApple OSS Distributions 		deallocate_page(allocs[i].addr);
298*4d495c6eSApple OSS Distributions 	}
299*4d495c6eSApple OSS Distributions }
300