xref: /xnu-8796.101.5/tests/vm/vm_ranges.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1*aca3beaaSApple OSS Distributions #include <darwintest.h>
2*aca3beaaSApple OSS Distributions #include <darwintest_utils.h>
3*aca3beaaSApple OSS Distributions 
4*aca3beaaSApple OSS Distributions #include <sys/types.h>
5*aca3beaaSApple OSS Distributions #include <sys/sysctl.h>
6*aca3beaaSApple OSS Distributions #include <mach/mach.h>
7*aca3beaaSApple OSS Distributions #include <mach/mach_vm.h>
8*aca3beaaSApple OSS Distributions #include <mach/vm_types.h>
9*aca3beaaSApple OSS Distributions #include <sys/mman.h>
10*aca3beaaSApple OSS Distributions #include <unistd.h>
11*aca3beaaSApple OSS Distributions #include <TargetConditionals.h>
12*aca3beaaSApple OSS Distributions 
13*aca3beaaSApple OSS Distributions typedef void (*child_test)(void);
14*aca3beaaSApple OSS Distributions 
15*aca3beaaSApple OSS Distributions enum {
16*aca3beaaSApple OSS Distributions 	DEFAULT = 0,
17*aca3beaaSApple OSS Distributions 	HEAP
18*aca3beaaSApple OSS Distributions };
19*aca3beaaSApple OSS Distributions 
20*aca3beaaSApple OSS Distributions static vm_size_t _allocation_size = 0;
21*aca3beaaSApple OSS Distributions static char _filepath[MAXPATHLEN];
22*aca3beaaSApple OSS Distributions static struct mach_vm_range parent_default;
23*aca3beaaSApple OSS Distributions static struct mach_vm_range parent_heap;
24*aca3beaaSApple OSS Distributions 
25*aca3beaaSApple OSS Distributions #define CHILD_PROCESS_COUNT     (20)
26*aca3beaaSApple OSS Distributions #define MAX_VM_ADDRESS          (0xFC0000000ULL)
27*aca3beaaSApple OSS Distributions 
28*aca3beaaSApple OSS Distributions /*
29*aca3beaaSApple OSS Distributions  * Choose an arbitrary memory tag which applies to each of default/heap range
30*aca3beaaSApple OSS Distributions  * for testing placement of allocations.
31*aca3beaaSApple OSS Distributions  */
32*aca3beaaSApple OSS Distributions #define VM_MEMORY_RANGE_DEFAULT (VM_MAKE_TAG(VM_MEMORY_STACK))
33*aca3beaaSApple OSS Distributions #define VM_MEMORY_RANGE_HEAP    (VM_MAKE_TAG(VM_MEMORY_MALLOC))
34*aca3beaaSApple OSS Distributions 
35*aca3beaaSApple OSS Distributions #define RANGE_DEFAULT_FLAGS     (VM_FLAGS_ANYWHERE | VM_MEMORY_RANGE_DEFAULT)
36*aca3beaaSApple OSS Distributions #define RANGE_HEAP_FLAGS        (VM_FLAGS_ANYWHERE | VM_MEMORY_RANGE_HEAP)
37*aca3beaaSApple OSS Distributions 
38*aca3beaaSApple OSS Distributions #define TARGET_OS_OTHER 0
39*aca3beaaSApple OSS Distributions 
40*aca3beaaSApple OSS Distributions T_GLOBAL_META(
41*aca3beaaSApple OSS Distributions 	T_META_NAMESPACE("xnu.vm"),
42*aca3beaaSApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
43*aca3beaaSApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"),
44*aca3beaaSApple OSS Distributions 	T_META_ENABLED(TARGET_OS_IOS || TARGET_OS_OTHER),
45*aca3beaaSApple OSS Distributions 	T_META_OWNER("mmorran")
46*aca3beaaSApple OSS Distributions 	);
47*aca3beaaSApple OSS Distributions 
48*aca3beaaSApple OSS Distributions static void
set_allocation_size(size_t sz)49*aca3beaaSApple OSS Distributions set_allocation_size(size_t sz)
50*aca3beaaSApple OSS Distributions {
51*aca3beaaSApple OSS Distributions 	_allocation_size = sz;
52*aca3beaaSApple OSS Distributions }
53*aca3beaaSApple OSS Distributions 
54*aca3beaaSApple OSS Distributions static bool
ranges_enabled(void)55*aca3beaaSApple OSS Distributions ranges_enabled(void)
56*aca3beaaSApple OSS Distributions {
57*aca3beaaSApple OSS Distributions 	struct mach_vm_range range;
58*aca3beaaSApple OSS Distributions 	size_t range_sz = sizeof(range);
59*aca3beaaSApple OSS Distributions 
60*aca3beaaSApple OSS Distributions 	bzero(&range, sizeof(range));
61*aca3beaaSApple OSS Distributions 
62*aca3beaaSApple OSS Distributions 	/*
63*aca3beaaSApple OSS Distributions 	 * We will fail with ENOENT or EINVAL if ranges are either not supported
64*aca3beaaSApple OSS Distributions 	 * or not enabled on our process.
65*aca3beaaSApple OSS Distributions 	 */
66*aca3beaaSApple OSS Distributions 	return sysctlbyname("vm.vm_map_user_range_default",
67*aca3beaaSApple OSS Distributions 	           &range, &range_sz, NULL, 0) == 0;
68*aca3beaaSApple OSS Distributions }
69*aca3beaaSApple OSS Distributions 
70*aca3beaaSApple OSS Distributions static void
71*aca3beaaSApple OSS Distributions do_test(void (^test)(void))
72*aca3beaaSApple OSS Distributions {
73*aca3beaaSApple OSS Distributions 	if (!ranges_enabled()) {
74*aca3beaaSApple OSS Distributions 		T_SKIP("VM map ranges not enabled");
75*aca3beaaSApple OSS Distributions 	}
76*aca3beaaSApple OSS Distributions 
77*aca3beaaSApple OSS Distributions 	test();
78*aca3beaaSApple OSS Distributions }
79*aca3beaaSApple OSS Distributions 
80*aca3beaaSApple OSS Distributions static struct mach_vm_range
get_range(int target_range)81*aca3beaaSApple OSS Distributions get_range(int target_range)
82*aca3beaaSApple OSS Distributions {
83*aca3beaaSApple OSS Distributions 	int ret = EINVAL;
84*aca3beaaSApple OSS Distributions 	struct mach_vm_range range;
85*aca3beaaSApple OSS Distributions 	size_t range_sz = sizeof(range);
86*aca3beaaSApple OSS Distributions 
87*aca3beaaSApple OSS Distributions 	bzero(&range, sizeof(range));
88*aca3beaaSApple OSS Distributions 
89*aca3beaaSApple OSS Distributions 	switch (target_range) {
90*aca3beaaSApple OSS Distributions 	case DEFAULT:
91*aca3beaaSApple OSS Distributions 		ret = sysctlbyname("vm.vm_map_user_range_default", &range, &range_sz, NULL, 0);
92*aca3beaaSApple OSS Distributions 		T_QUIET;
93*aca3beaaSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "successfully retrieved user default range");
94*aca3beaaSApple OSS Distributions 		break;
95*aca3beaaSApple OSS Distributions 
96*aca3beaaSApple OSS Distributions 	case HEAP:
97*aca3beaaSApple OSS Distributions 		ret = sysctlbyname("vm.vm_map_user_range_heap", &range, &range_sz, NULL, 0);
98*aca3beaaSApple OSS Distributions 		T_QUIET;
99*aca3beaaSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "successfully retrieved user heap range");
100*aca3beaaSApple OSS Distributions 		break;
101*aca3beaaSApple OSS Distributions 
102*aca3beaaSApple OSS Distributions 	default:
103*aca3beaaSApple OSS Distributions 		/* Fall through with EINVAL */
104*aca3beaaSApple OSS Distributions 		break;
105*aca3beaaSApple OSS Distributions 	}
106*aca3beaaSApple OSS Distributions 
107*aca3beaaSApple OSS Distributions 	return range;
108*aca3beaaSApple OSS Distributions }
109*aca3beaaSApple OSS Distributions 
110*aca3beaaSApple OSS Distributions static mach_vm_address_t
assert_allocate(mach_vm_address_t dst,int vm_flags)111*aca3beaaSApple OSS Distributions assert_allocate(mach_vm_address_t dst, int vm_flags)
112*aca3beaaSApple OSS Distributions {
113*aca3beaaSApple OSS Distributions 	int ret = mach_vm_allocate(mach_task_self(), &dst, _allocation_size, vm_flags);
114*aca3beaaSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(ret, "vm_allocate");
115*aca3beaaSApple OSS Distributions 	return dst;
116*aca3beaaSApple OSS Distributions }
117*aca3beaaSApple OSS Distributions 
118*aca3beaaSApple OSS Distributions static void
assert_in_range(struct mach_vm_range range,mach_vm_offset_t addr)119*aca3beaaSApple OSS Distributions assert_in_range(struct mach_vm_range range, mach_vm_offset_t addr)
120*aca3beaaSApple OSS Distributions {
121*aca3beaaSApple OSS Distributions 	T_LOG("checking if %llx <= %llx <= %llx", range.min_address, addr,
122*aca3beaaSApple OSS Distributions 	    range.max_address);
123*aca3beaaSApple OSS Distributions 	T_EXPECT_GE(addr, range.min_address, "allocation above heap min address");
124*aca3beaaSApple OSS Distributions 	T_EXPECT_LE(addr, range.max_address, "allocation below heap max address");
125*aca3beaaSApple OSS Distributions }
126*aca3beaaSApple OSS Distributions 
127*aca3beaaSApple OSS Distributions static void
assert_in_heap_range(mach_vm_offset_t addr)128*aca3beaaSApple OSS Distributions assert_in_heap_range(mach_vm_offset_t addr)
129*aca3beaaSApple OSS Distributions {
130*aca3beaaSApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
131*aca3beaaSApple OSS Distributions 
132*aca3beaaSApple OSS Distributions 	assert_in_range(range, addr);
133*aca3beaaSApple OSS Distributions }
134*aca3beaaSApple OSS Distributions 
135*aca3beaaSApple OSS Distributions static void *
assert_mmap(void * addr,int fd,int flags)136*aca3beaaSApple OSS Distributions assert_mmap(void *addr, int fd, int flags)
137*aca3beaaSApple OSS Distributions {
138*aca3beaaSApple OSS Distributions 	void *ret = mmap(addr, _allocation_size, VM_PROT_READ | VM_PROT_WRITE,
139*aca3beaaSApple OSS Distributions 	    flags, fd, 0);
140*aca3beaaSApple OSS Distributions 	T_EXPECT_NE(ret, MAP_FAILED, "mmap should not have MAP_FAILED");
141*aca3beaaSApple OSS Distributions 	T_EXPECT_NE(ret, NULL, "mmap should have returned a valid pointer");
142*aca3beaaSApple OSS Distributions 	return ret;
143*aca3beaaSApple OSS Distributions }
144*aca3beaaSApple OSS Distributions 
145*aca3beaaSApple OSS Distributions static void
assert_allocate_eq(mach_vm_address_t dst,int vm_flags)146*aca3beaaSApple OSS Distributions assert_allocate_eq(mach_vm_address_t dst, int vm_flags)
147*aca3beaaSApple OSS Distributions {
148*aca3beaaSApple OSS Distributions 	mach_vm_address_t target = dst;
149*aca3beaaSApple OSS Distributions 
150*aca3beaaSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(mach_vm_allocate(mach_task_self(), &target,
151*aca3beaaSApple OSS Distributions 	    _allocation_size, vm_flags), "vm_allocate");
152*aca3beaaSApple OSS Distributions 
153*aca3beaaSApple OSS Distributions 	T_EXPECT_EQ(target, dst, "target/dst differ");
154*aca3beaaSApple OSS Distributions }
155*aca3beaaSApple OSS Distributions 
156*aca3beaaSApple OSS Distributions static mach_vm_address_t
assert_allocate_in_range(int target_range,mach_vm_address_t dst,int vm_flags)157*aca3beaaSApple OSS Distributions assert_allocate_in_range(int target_range, mach_vm_address_t dst, int vm_flags)
158*aca3beaaSApple OSS Distributions {
159*aca3beaaSApple OSS Distributions 	struct mach_vm_range range = get_range(target_range);
160*aca3beaaSApple OSS Distributions 	dst = assert_allocate(dst, vm_flags);
161*aca3beaaSApple OSS Distributions 
162*aca3beaaSApple OSS Distributions 	assert_in_range(range, (mach_vm_offset_t)dst);
163*aca3beaaSApple OSS Distributions 
164*aca3beaaSApple OSS Distributions 	return dst;
165*aca3beaaSApple OSS Distributions }
166*aca3beaaSApple OSS Distributions 
167*aca3beaaSApple OSS Distributions static void *
assert_mmap_in_range(void * addr,int target_range,int fd,int flags)168*aca3beaaSApple OSS Distributions assert_mmap_in_range(void *addr, int target_range, int fd, int flags)
169*aca3beaaSApple OSS Distributions {
170*aca3beaaSApple OSS Distributions 	struct mach_vm_range range = get_range(target_range);
171*aca3beaaSApple OSS Distributions 	void *dst = assert_mmap(addr, fd, flags);
172*aca3beaaSApple OSS Distributions 
173*aca3beaaSApple OSS Distributions 	assert_in_range(range, (mach_vm_offset_t)dst);
174*aca3beaaSApple OSS Distributions 
175*aca3beaaSApple OSS Distributions 	return dst;
176*aca3beaaSApple OSS Distributions }
177*aca3beaaSApple OSS Distributions 
178*aca3beaaSApple OSS Distributions static void
fork_child_test(child_test func)179*aca3beaaSApple OSS Distributions fork_child_test(child_test func)
180*aca3beaaSApple OSS Distributions {
181*aca3beaaSApple OSS Distributions 	pid_t child_pid;
182*aca3beaaSApple OSS Distributions 	int err;
183*aca3beaaSApple OSS Distributions 
184*aca3beaaSApple OSS Distributions 	child_pid = fork();
185*aca3beaaSApple OSS Distributions 
186*aca3beaaSApple OSS Distributions 	if (child_pid == 0) {
187*aca3beaaSApple OSS Distributions 		/* child process */
188*aca3beaaSApple OSS Distributions 		func();
189*aca3beaaSApple OSS Distributions 		exit(0);
190*aca3beaaSApple OSS Distributions 	} else {
191*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(child_pid, "fork process");
192*aca3beaaSApple OSS Distributions 
193*aca3beaaSApple OSS Distributions 		/* wait for child process to exit */
194*aca3beaaSApple OSS Distributions 		if (dt_waitpid(child_pid, &err, NULL, 30) == false) {
195*aca3beaaSApple OSS Distributions 			T_FAIL("dt_waitpid() failed on child pid %d", child_pid);
196*aca3beaaSApple OSS Distributions 		}
197*aca3beaaSApple OSS Distributions 	}
198*aca3beaaSApple OSS Distributions }
199*aca3beaaSApple OSS Distributions 
200*aca3beaaSApple OSS Distributions static void
cleanup_file(void)201*aca3beaaSApple OSS Distributions cleanup_file(void)
202*aca3beaaSApple OSS Distributions {
203*aca3beaaSApple OSS Distributions 	unlink(_filepath);
204*aca3beaaSApple OSS Distributions 	bzero(_filepath, MAXPATHLEN);
205*aca3beaaSApple OSS Distributions }
206*aca3beaaSApple OSS Distributions 
207*aca3beaaSApple OSS Distributions T_DECL(range_allocate_heap,
208*aca3beaaSApple OSS Distributions     "ensure malloc tagged memory is allocated within the heap range")
209*aca3beaaSApple OSS Distributions {
210*aca3beaaSApple OSS Distributions 	do_test(^{
211*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
212*aca3beaaSApple OSS Distributions 		assert_allocate_in_range(HEAP, 0, RANGE_HEAP_FLAGS);
213*aca3beaaSApple OSS Distributions 	});
214*aca3beaaSApple OSS Distributions }
215*aca3beaaSApple OSS Distributions 
216*aca3beaaSApple OSS Distributions T_DECL(range_allocate_anywhere,
217*aca3beaaSApple OSS Distributions     "ensure allocation is within target range when hint is outwith range")
218*aca3beaaSApple OSS Distributions {
219*aca3beaaSApple OSS Distributions 	do_test(^{
220*aca3beaaSApple OSS Distributions 		struct mach_vm_range range = get_range(HEAP);
221*aca3beaaSApple OSS Distributions 
222*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
223*aca3beaaSApple OSS Distributions 		assert_allocate_in_range(HEAP, range.min_address - _allocation_size, RANGE_HEAP_FLAGS);
224*aca3beaaSApple OSS Distributions 	});
225*aca3beaaSApple OSS Distributions }
226*aca3beaaSApple OSS Distributions 
227*aca3beaaSApple OSS Distributions T_DECL(range_allocate_stack,
228*aca3beaaSApple OSS Distributions     "ensure a stack allocation is in the default range")
229*aca3beaaSApple OSS Distributions {
230*aca3beaaSApple OSS Distributions 	do_test(^{
231*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
232*aca3beaaSApple OSS Distributions 		assert_allocate_in_range(DEFAULT, 0, RANGE_DEFAULT_FLAGS);
233*aca3beaaSApple OSS Distributions 	});
234*aca3beaaSApple OSS Distributions }
235*aca3beaaSApple OSS Distributions 
236*aca3beaaSApple OSS Distributions static void
ensure_fixed_mappings_succeed_cross(int heap)237*aca3beaaSApple OSS Distributions ensure_fixed_mappings_succeed_cross(int heap)
238*aca3beaaSApple OSS Distributions {
239*aca3beaaSApple OSS Distributions 	vm_map_address_t addr;
240*aca3beaaSApple OSS Distributions 
241*aca3beaaSApple OSS Distributions 	addr = assert_allocate(0, VM_FLAGS_ANYWHERE | heap);
242*aca3beaaSApple OSS Distributions 	vm_deallocate(mach_task_self(), addr, _allocation_size);
243*aca3beaaSApple OSS Distributions 
244*aca3beaaSApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_MEMORY_RANGE_DEFAULT);
245*aca3beaaSApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MEMORY_RANGE_DEFAULT);
246*aca3beaaSApple OSS Distributions 	vm_deallocate(mach_task_self(), addr, _allocation_size);
247*aca3beaaSApple OSS Distributions 
248*aca3beaaSApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_MEMORY_RANGE_HEAP);
249*aca3beaaSApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MEMORY_RANGE_HEAP);
250*aca3beaaSApple OSS Distributions 	vm_deallocate(mach_task_self(), addr, _allocation_size);
251*aca3beaaSApple OSS Distributions }
252*aca3beaaSApple OSS Distributions 
253*aca3beaaSApple OSS Distributions static void
ensure_rogue_fixed_fails(void)254*aca3beaaSApple OSS Distributions ensure_rogue_fixed_fails(void)
255*aca3beaaSApple OSS Distributions {
256*aca3beaaSApple OSS Distributions 	struct mach_vm_range def = get_range(DEFAULT);
257*aca3beaaSApple OSS Distributions 	struct mach_vm_range heap = get_range(HEAP);
258*aca3beaaSApple OSS Distributions 	mach_vm_address_t addr;
259*aca3beaaSApple OSS Distributions 	kern_return_t kr;
260*aca3beaaSApple OSS Distributions 
261*aca3beaaSApple OSS Distributions 	if (def.max_address + 3 * _allocation_size <= heap.min_address) {
262*aca3beaaSApple OSS Distributions 		addr = heap.min_address - 2 * _allocation_size;
263*aca3beaaSApple OSS Distributions 	} else {
264*aca3beaaSApple OSS Distributions 		/*
265*aca3beaaSApple OSS Distributions 		 * in the unlikely event when there's no space
266*aca3beaaSApple OSS Distributions 		 * between default and heap, then there must be
267*aca3beaaSApple OSS Distributions 		 * a hole after heap.
268*aca3beaaSApple OSS Distributions 		 */
269*aca3beaaSApple OSS Distributions 		addr = heap.max_address + _allocation_size;
270*aca3beaaSApple OSS Distributions 	}
271*aca3beaaSApple OSS Distributions 
272*aca3beaaSApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr,
273*aca3beaaSApple OSS Distributions 	    _allocation_size, VM_FLAGS_FIXED);
274*aca3beaaSApple OSS Distributions 	T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ADDRESS, "should fail");
275*aca3beaaSApple OSS Distributions }
276*aca3beaaSApple OSS Distributions 
277*aca3beaaSApple OSS Distributions static void
ensure_fixed_mapping(void)278*aca3beaaSApple OSS Distributions ensure_fixed_mapping(void)
279*aca3beaaSApple OSS Distributions {
280*aca3beaaSApple OSS Distributions 	set_allocation_size(PAGE_SIZE);
281*aca3beaaSApple OSS Distributions 
282*aca3beaaSApple OSS Distributions 	ensure_fixed_mappings_succeed_cross(VM_MEMORY_RANGE_DEFAULT);
283*aca3beaaSApple OSS Distributions 	ensure_fixed_mappings_succeed_cross(VM_MEMORY_RANGE_HEAP);
284*aca3beaaSApple OSS Distributions 
285*aca3beaaSApple OSS Distributions 	ensure_rogue_fixed_fails();
286*aca3beaaSApple OSS Distributions }
287*aca3beaaSApple OSS Distributions 
288*aca3beaaSApple OSS Distributions T_DECL(range_allocate_fixed, "ensure fixed target is honored (even with an incorrect tag)")
289*aca3beaaSApple OSS Distributions {
290*aca3beaaSApple OSS Distributions 	do_test(^{
291*aca3beaaSApple OSS Distributions 		ensure_fixed_mapping();
292*aca3beaaSApple OSS Distributions 		fork_child_test(ensure_fixed_mapping);
293*aca3beaaSApple OSS Distributions 	});
294*aca3beaaSApple OSS Distributions }
295*aca3beaaSApple OSS Distributions 
296*aca3beaaSApple OSS Distributions T_DECL(range_mmap_anon, "ensure anon mapping within HEAP range")
297*aca3beaaSApple OSS Distributions {
298*aca3beaaSApple OSS Distributions 	do_test(^{
299*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
300*aca3beaaSApple OSS Distributions 
301*aca3beaaSApple OSS Distributions 		assert_mmap_in_range(NULL, HEAP, -1, MAP_ANON | MAP_PRIVATE);
302*aca3beaaSApple OSS Distributions 	});
303*aca3beaaSApple OSS Distributions }
304*aca3beaaSApple OSS Distributions 
305*aca3beaaSApple OSS Distributions T_DECL(range_mmap_file, "ensure file is mapped within HEAP range")
306*aca3beaaSApple OSS Distributions {
307*aca3beaaSApple OSS Distributions 	do_test(^{
308*aca3beaaSApple OSS Distributions 		int fd = -1;
309*aca3beaaSApple OSS Distributions 
310*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
311*aca3beaaSApple OSS Distributions 
312*aca3beaaSApple OSS Distributions 		/* prepare temp file */
313*aca3beaaSApple OSS Distributions 		strncpy(_filepath, "/tmp/mapfile.XXXXXX", MAXPATHLEN);
314*aca3beaaSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(fd = mkstemp(_filepath), NULL);
315*aca3beaaSApple OSS Distributions 		atexit(cleanup_file);
316*aca3beaaSApple OSS Distributions 
317*aca3beaaSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ftruncate(fd, (off_t)_allocation_size), NULL);
318*aca3beaaSApple OSS Distributions 
319*aca3beaaSApple OSS Distributions 		/* map it in to the heap rage */
320*aca3beaaSApple OSS Distributions 		T_LOG("mapping file in HEAP range");
321*aca3beaaSApple OSS Distributions 		assert_mmap_in_range(NULL, HEAP, fd, MAP_FILE | MAP_SHARED);
322*aca3beaaSApple OSS Distributions 	});
323*aca3beaaSApple OSS Distributions }
324*aca3beaaSApple OSS Distributions 
325*aca3beaaSApple OSS Distributions 
326*aca3beaaSApple OSS Distributions T_DECL(range_mmap_alias_tag, "ensure anon mapping with tag is honored")
327*aca3beaaSApple OSS Distributions {
328*aca3beaaSApple OSS Distributions 	do_test(^{
329*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
330*aca3beaaSApple OSS Distributions 		assert_mmap_in_range(NULL, DEFAULT, VM_MEMORY_RANGE_DEFAULT, MAP_ANON | MAP_PRIVATE);
331*aca3beaaSApple OSS Distributions 	});
332*aca3beaaSApple OSS Distributions }
333*aca3beaaSApple OSS Distributions 
334*aca3beaaSApple OSS Distributions T_DECL(range_mmap_with_low_hint,
335*aca3beaaSApple OSS Distributions     "ensure allocation is within target range when hint is below range")
336*aca3beaaSApple OSS Distributions {
337*aca3beaaSApple OSS Distributions 	do_test(^{
338*aca3beaaSApple OSS Distributions 		struct mach_vm_range range = get_range(HEAP);
339*aca3beaaSApple OSS Distributions 		mach_vm_address_t target = range.min_address - _allocation_size;
340*aca3beaaSApple OSS Distributions 
341*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
342*aca3beaaSApple OSS Distributions 		assert_mmap_in_range((void *)target, HEAP, -1, MAP_ANON | MAP_PRIVATE);
343*aca3beaaSApple OSS Distributions 	});
344*aca3beaaSApple OSS Distributions }
345*aca3beaaSApple OSS Distributions 
346*aca3beaaSApple OSS Distributions T_DECL(range_mmap_with_high_hint,
347*aca3beaaSApple OSS Distributions     "ensure allocation is within target range when hint is within range")
348*aca3beaaSApple OSS Distributions {
349*aca3beaaSApple OSS Distributions 	do_test(^{
350*aca3beaaSApple OSS Distributions 		struct mach_vm_range range = get_range(HEAP);
351*aca3beaaSApple OSS Distributions 		mach_vm_address_t target = range.min_address + 0x100000000;
352*aca3beaaSApple OSS Distributions 
353*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
354*aca3beaaSApple OSS Distributions 		void *dst = assert_mmap_in_range((void *)target, HEAP, -1, MAP_ANON | MAP_PRIVATE);
355*aca3beaaSApple OSS Distributions 
356*aca3beaaSApple OSS Distributions 		T_EXPECT_EQ((mach_vm_address_t)dst, target, "unexpected allocation address");
357*aca3beaaSApple OSS Distributions 	});
358*aca3beaaSApple OSS Distributions }
359*aca3beaaSApple OSS Distributions 
360*aca3beaaSApple OSS Distributions T_DECL(range_mmap_with_bad_hint,
361*aca3beaaSApple OSS Distributions     "ensure allocation fails when hint is above range")
362*aca3beaaSApple OSS Distributions {
363*aca3beaaSApple OSS Distributions 	do_test(^{
364*aca3beaaSApple OSS Distributions 		struct mach_vm_range range = get_range(HEAP);
365*aca3beaaSApple OSS Distributions 		mach_vm_address_t target = range.max_address + 0x100000000;
366*aca3beaaSApple OSS Distributions 
367*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
368*aca3beaaSApple OSS Distributions 
369*aca3beaaSApple OSS Distributions 		/* mmap should retry with 0 base on initial KERN_NO_SPACE failure */
370*aca3beaaSApple OSS Distributions 		assert_mmap_in_range((void *)target, HEAP, -1, MAP_ANON | MAP_PRIVATE);
371*aca3beaaSApple OSS Distributions 	});
372*aca3beaaSApple OSS Distributions }
373*aca3beaaSApple OSS Distributions 
374*aca3beaaSApple OSS Distributions T_DECL(range_mach_vm_map_with_bad_hint,
375*aca3beaaSApple OSS Distributions     "ensure mach_vm_map fails when hint is above range")
376*aca3beaaSApple OSS Distributions {
377*aca3beaaSApple OSS Distributions 	do_test(^{
378*aca3beaaSApple OSS Distributions 		struct mach_vm_range range = get_range(HEAP);
379*aca3beaaSApple OSS Distributions 		mach_vm_address_t addr = range.max_address + 0x100000000;
380*aca3beaaSApple OSS Distributions 
381*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
382*aca3beaaSApple OSS Distributions 
383*aca3beaaSApple OSS Distributions 		/*
384*aca3beaaSApple OSS Distributions 		 * unlike mmap & vm_allocate, mach_vm_map should fail when given a hint
385*aca3beaaSApple OSS Distributions 		 * out with the target range.
386*aca3beaaSApple OSS Distributions 		 */
387*aca3beaaSApple OSS Distributions 		int ret = mach_vm_map(mach_task_self(), &addr, _allocation_size,
388*aca3beaaSApple OSS Distributions 		(mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, MACH_PORT_NULL,
389*aca3beaaSApple OSS Distributions 		(memory_object_offset_t)0, FALSE, VM_PROT_DEFAULT, VM_PROT_ALL,
390*aca3beaaSApple OSS Distributions 		VM_INHERIT_DEFAULT);
391*aca3beaaSApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, KERN_NO_SPACE, "expected KERN_NO_SPACE");
392*aca3beaaSApple OSS Distributions 	});
393*aca3beaaSApple OSS Distributions }
394*aca3beaaSApple OSS Distributions 
395*aca3beaaSApple OSS Distributions T_DECL(range_mach_vm_remap_default,
396*aca3beaaSApple OSS Distributions     "ensure mach_vm_remap is successful in default range")
397*aca3beaaSApple OSS Distributions {
398*aca3beaaSApple OSS Distributions 	do_test(^{
399*aca3beaaSApple OSS Distributions 		vm_prot_t curprot;
400*aca3beaaSApple OSS Distributions 		vm_prot_t maxprot;
401*aca3beaaSApple OSS Distributions 
402*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
403*aca3beaaSApple OSS Distributions 
404*aca3beaaSApple OSS Distributions 		mach_vm_address_t addr = assert_allocate_in_range(DEFAULT, 0, RANGE_DEFAULT_FLAGS);
405*aca3beaaSApple OSS Distributions 		mach_vm_address_t target = addr + _allocation_size;
406*aca3beaaSApple OSS Distributions 
407*aca3beaaSApple OSS Distributions 		int ret = mach_vm_remap(mach_task_self(), &target, _allocation_size,
408*aca3beaaSApple OSS Distributions 		(mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, mach_task_self(),
409*aca3beaaSApple OSS Distributions 		addr, FALSE, &curprot, &maxprot, VM_INHERIT_NONE);
410*aca3beaaSApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, KERN_SUCCESS, "expected KERN_SUCCESS");
411*aca3beaaSApple OSS Distributions 	});
412*aca3beaaSApple OSS Distributions }
413*aca3beaaSApple OSS Distributions 
414*aca3beaaSApple OSS Distributions T_DECL(range_mach_vm_remap_heap_with_hint,
415*aca3beaaSApple OSS Distributions     "ensure mach_vm_remap is successful in heap range")
416*aca3beaaSApple OSS Distributions {
417*aca3beaaSApple OSS Distributions 	do_test(^{
418*aca3beaaSApple OSS Distributions 		vm_prot_t curprot;
419*aca3beaaSApple OSS Distributions 		vm_prot_t maxprot;
420*aca3beaaSApple OSS Distributions 
421*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
422*aca3beaaSApple OSS Distributions 
423*aca3beaaSApple OSS Distributions 		mach_vm_address_t addr = assert_allocate_in_range(HEAP, 0, RANGE_HEAP_FLAGS);
424*aca3beaaSApple OSS Distributions 		mach_vm_address_t target = addr + _allocation_size;
425*aca3beaaSApple OSS Distributions 
426*aca3beaaSApple OSS Distributions 		int ret = mach_vm_remap(mach_task_self(), &target, _allocation_size,
427*aca3beaaSApple OSS Distributions 		(mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, mach_task_self(),
428*aca3beaaSApple OSS Distributions 		addr, FALSE, &curprot, &maxprot, VM_INHERIT_NONE);
429*aca3beaaSApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, KERN_SUCCESS, "expected KERN_SUCCESS");
430*aca3beaaSApple OSS Distributions 		assert_in_heap_range(target);
431*aca3beaaSApple OSS Distributions 	});
432*aca3beaaSApple OSS Distributions }
433*aca3beaaSApple OSS Distributions 
434*aca3beaaSApple OSS Distributions T_DECL(range_mach_vm_remap_heap,
435*aca3beaaSApple OSS Distributions     "ensure mach_vm_remap remains in same range")
436*aca3beaaSApple OSS Distributions {
437*aca3beaaSApple OSS Distributions 	do_test(^{
438*aca3beaaSApple OSS Distributions 		vm_prot_t curprot;
439*aca3beaaSApple OSS Distributions 		vm_prot_t maxprot;
440*aca3beaaSApple OSS Distributions 
441*aca3beaaSApple OSS Distributions 		set_allocation_size(PAGE_SIZE);
442*aca3beaaSApple OSS Distributions 
443*aca3beaaSApple OSS Distributions 		mach_vm_address_t addr = assert_allocate_in_range(HEAP, 0, RANGE_HEAP_FLAGS);
444*aca3beaaSApple OSS Distributions 		mach_vm_address_t target = 0;
445*aca3beaaSApple OSS Distributions 
446*aca3beaaSApple OSS Distributions 		int ret = mach_vm_remap(mach_task_self(), &target, _allocation_size,
447*aca3beaaSApple OSS Distributions 		(mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, mach_task_self(),
448*aca3beaaSApple OSS Distributions 		addr, FALSE, &curprot, &maxprot, VM_INHERIT_NONE);
449*aca3beaaSApple OSS Distributions 		T_EXPECT_EQ(ret, KERN_SUCCESS, "expected KERN_SUCCESS");
450*aca3beaaSApple OSS Distributions 		assert_in_heap_range(target);
451*aca3beaaSApple OSS Distributions 	});
452*aca3beaaSApple OSS Distributions }
453*aca3beaaSApple OSS Distributions 
454*aca3beaaSApple OSS Distributions static void
ensure_range(void)455*aca3beaaSApple OSS Distributions ensure_range(void)
456*aca3beaaSApple OSS Distributions {
457*aca3beaaSApple OSS Distributions 	struct mach_vm_range def = get_range(DEFAULT);
458*aca3beaaSApple OSS Distributions 	struct mach_vm_range heap = get_range(HEAP);
459*aca3beaaSApple OSS Distributions 
460*aca3beaaSApple OSS Distributions 	T_EXPECT_GT(heap.min_address, def.max_address,
461*aca3beaaSApple OSS Distributions 	    "ranges should not overlap");
462*aca3beaaSApple OSS Distributions 	T_EXPECT_LE(heap.max_address, MAX_VM_ADDRESS,
463*aca3beaaSApple OSS Distributions 	    "expected max <= %llx", MAX_VM_ADDRESS);
464*aca3beaaSApple OSS Distributions 	T_EXPECT_EQ(heap.min_address,
465*aca3beaaSApple OSS Distributions 	    heap.min_address & (unsigned long)~0x1FFFFF,
466*aca3beaaSApple OSS Distributions 	    "expected alignment on 2MB TT boundary");
467*aca3beaaSApple OSS Distributions }
468*aca3beaaSApple OSS Distributions 
469*aca3beaaSApple OSS Distributions static void
ensure_child_range(void)470*aca3beaaSApple OSS Distributions ensure_child_range(void)
471*aca3beaaSApple OSS Distributions {
472*aca3beaaSApple OSS Distributions 	struct mach_vm_range def = get_range(DEFAULT);
473*aca3beaaSApple OSS Distributions 	struct mach_vm_range heap = get_range(HEAP);
474*aca3beaaSApple OSS Distributions 
475*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(def.min_address, parent_default.min_address,
476*aca3beaaSApple OSS Distributions 	    "expected forked default min to be equal");
477*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(def.max_address, parent_default.max_address,
478*aca3beaaSApple OSS Distributions 	    "expected forked default max to be equal");
479*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(heap.min_address, parent_heap.min_address,
480*aca3beaaSApple OSS Distributions 	    "expected forked heap min to be equal");
481*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(heap.max_address, parent_heap.max_address,
482*aca3beaaSApple OSS Distributions 	    "expected forked heap max to be equal");
483*aca3beaaSApple OSS Distributions }
484*aca3beaaSApple OSS Distributions 
485*aca3beaaSApple OSS Distributions T_DECL(range_ensure_bounds, "ensure ranges respect map bounds")
486*aca3beaaSApple OSS Distributions {
487*aca3beaaSApple OSS Distributions 	do_test(^{
488*aca3beaaSApple OSS Distributions 		parent_default = get_range(DEFAULT);
489*aca3beaaSApple OSS Distributions 		parent_heap = get_range(HEAP);
490*aca3beaaSApple OSS Distributions 
491*aca3beaaSApple OSS Distributions 		ensure_range();
492*aca3beaaSApple OSS Distributions 
493*aca3beaaSApple OSS Distributions 		for (uint32_t i = 0; i < CHILD_PROCESS_COUNT; i++) {
494*aca3beaaSApple OSS Distributions 		        fork_child_test(ensure_child_range);
495*aca3beaaSApple OSS Distributions 		}
496*aca3beaaSApple OSS Distributions 	});
497*aca3beaaSApple OSS Distributions }
498