xref: /xnu-11215.61.5/tests/vm/vm_ranges.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions #include <darwintest.h>
2*4f1223e8SApple OSS Distributions #include <darwintest_utils.h>
3*4f1223e8SApple OSS Distributions 
4*4f1223e8SApple OSS Distributions #include <sys/types.h>
5*4f1223e8SApple OSS Distributions #include <sys/sysctl.h>
6*4f1223e8SApple OSS Distributions #include <mach/mach.h>
7*4f1223e8SApple OSS Distributions #include <mach/mach_vm.h>
8*4f1223e8SApple OSS Distributions #include <mach/task_info.h>
9*4f1223e8SApple OSS Distributions #include <mach/vm_param.h>
10*4f1223e8SApple OSS Distributions #include <mach/vm_types.h>
11*4f1223e8SApple OSS Distributions #include <sys/mman.h>
12*4f1223e8SApple OSS Distributions #include <unistd.h>
13*4f1223e8SApple OSS Distributions #include <TargetConditionals.h>
14*4f1223e8SApple OSS Distributions 
15*4f1223e8SApple OSS Distributions enum {
16*4f1223e8SApple OSS Distributions 	DEFAULT = 0,
17*4f1223e8SApple OSS Distributions 	HEAP,
18*4f1223e8SApple OSS Distributions 	LARGE_FILE
19*4f1223e8SApple OSS Distributions };
20*4f1223e8SApple OSS Distributions 
21*4f1223e8SApple OSS Distributions static char _filepath[MAXPATHLEN];
22*4f1223e8SApple OSS Distributions static struct mach_vm_range parent_default;
23*4f1223e8SApple OSS Distributions static struct mach_vm_range parent_heap;
24*4f1223e8SApple OSS Distributions 
25*4f1223e8SApple OSS Distributions #define CHILD_PROCESS_COUNT     (20)
26*4f1223e8SApple OSS Distributions #undef KiB
27*4f1223e8SApple OSS Distributions #undef MiB
28*4f1223e8SApple OSS Distributions #undef GiB
29*4f1223e8SApple OSS Distributions #define KiB(x)  ((uint64_t)(x) << 10)
30*4f1223e8SApple OSS Distributions #define MiB(x)  ((uint64_t)(x) << 20)
31*4f1223e8SApple OSS Distributions #define GiB(x)  ((uint64_t)(x) << 30)
32*4f1223e8SApple OSS Distributions 
33*4f1223e8SApple OSS Distributions #define ALLOCATION_SIZE (PAGE_SIZE)
34*4f1223e8SApple OSS Distributions #define LARGE_ALLOCATION_SIZE (GiB(1))
35*4f1223e8SApple OSS Distributions #define PER_ALLOC_AMT_GB (GiB(256))
36*4f1223e8SApple OSS Distributions #define N_ALLOC 5
37*4f1223e8SApple OSS Distributions 
38*4f1223e8SApple OSS Distributions 
39*4f1223e8SApple OSS Distributions /*
40*4f1223e8SApple OSS Distributions  * Choose an arbitrary memory tag which applies to each of default/heap range
41*4f1223e8SApple OSS Distributions  * for testing placement of allocations.
42*4f1223e8SApple OSS Distributions  */
43*4f1223e8SApple OSS Distributions #define VM_MEMORY_RANGE_DEFAULT (VM_MAKE_TAG(VM_MEMORY_STACK))
44*4f1223e8SApple OSS Distributions #define VM_MEMORY_RANGE_HEAP    (VM_MAKE_TAG(VM_MEMORY_MALLOC_SMALL))
45*4f1223e8SApple OSS Distributions 
46*4f1223e8SApple OSS Distributions #define RANGE_DEFAULT_FLAGS     (VM_FLAGS_ANYWHERE | VM_MEMORY_RANGE_DEFAULT)
47*4f1223e8SApple OSS Distributions #define RANGE_HEAP_FLAGS        (VM_FLAGS_ANYWHERE | VM_MEMORY_RANGE_HEAP)
48*4f1223e8SApple OSS Distributions 
49*4f1223e8SApple OSS Distributions T_GLOBAL_META(
50*4f1223e8SApple OSS Distributions 	T_META_NAMESPACE("xnu.vm"),
51*4f1223e8SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
52*4f1223e8SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"),
53*4f1223e8SApple OSS Distributions 	T_META_ENABLED(!TARGET_OS_OSX),
54*4f1223e8SApple OSS Distributions 	T_META_OWNER("mmorran")
55*4f1223e8SApple OSS Distributions 	);
56*4f1223e8SApple OSS Distributions 
57*4f1223e8SApple OSS Distributions static bool
ranges_enabled(void)58*4f1223e8SApple OSS Distributions ranges_enabled(void)
59*4f1223e8SApple OSS Distributions {
60*4f1223e8SApple OSS Distributions 	struct mach_vm_range range;
61*4f1223e8SApple OSS Distributions 	size_t range_sz = sizeof(range);
62*4f1223e8SApple OSS Distributions 
63*4f1223e8SApple OSS Distributions 	bzero(&range, sizeof(range));
64*4f1223e8SApple OSS Distributions 
65*4f1223e8SApple OSS Distributions 	/*
66*4f1223e8SApple OSS Distributions 	 * We will fail with ENOENT or EINVAL if ranges are either not supported
67*4f1223e8SApple OSS Distributions 	 * or not enabled on our process.
68*4f1223e8SApple OSS Distributions 	 */
69*4f1223e8SApple OSS Distributions 	return sysctlbyname("vm.vm_map_user_range_default",
70*4f1223e8SApple OSS Distributions 	           &range, &range_sz, NULL, 0) == 0;
71*4f1223e8SApple OSS Distributions }
72*4f1223e8SApple OSS Distributions 
73*4f1223e8SApple OSS Distributions #define CHECK_RANGES_ENABLED() \
74*4f1223e8SApple OSS Distributions 	if (!ranges_enabled()) { \
75*4f1223e8SApple OSS Distributions 	        T_SKIP("VM map ranges not enabled"); \
76*4f1223e8SApple OSS Distributions 	}
77*4f1223e8SApple OSS Distributions 
78*4f1223e8SApple OSS Distributions static struct mach_vm_range
get_range(int target_range)79*4f1223e8SApple OSS Distributions get_range(int target_range)
80*4f1223e8SApple OSS Distributions {
81*4f1223e8SApple OSS Distributions 	int ret = EINVAL;
82*4f1223e8SApple OSS Distributions 	struct mach_vm_range range;
83*4f1223e8SApple OSS Distributions 	size_t range_sz = sizeof(range);
84*4f1223e8SApple OSS Distributions 
85*4f1223e8SApple OSS Distributions 	bzero(&range, sizeof(range));
86*4f1223e8SApple OSS Distributions 
87*4f1223e8SApple OSS Distributions 	switch (target_range) {
88*4f1223e8SApple OSS Distributions 	case DEFAULT:
89*4f1223e8SApple OSS Distributions 		ret = sysctlbyname("vm.vm_map_user_range_default", &range, &range_sz, NULL, 0);
90*4f1223e8SApple OSS Distributions 		T_QUIET;
91*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "successfully retrieved user default range");
92*4f1223e8SApple OSS Distributions 		break;
93*4f1223e8SApple OSS Distributions 
94*4f1223e8SApple OSS Distributions 	case HEAP:
95*4f1223e8SApple OSS Distributions 		ret = sysctlbyname("vm.vm_map_user_range_heap", &range, &range_sz, NULL, 0);
96*4f1223e8SApple OSS Distributions 		T_QUIET;
97*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "successfully retrieved user heap range");
98*4f1223e8SApple OSS Distributions 		break;
99*4f1223e8SApple OSS Distributions 
100*4f1223e8SApple OSS Distributions 	case LARGE_FILE:
101*4f1223e8SApple OSS Distributions 		ret = sysctlbyname("vm.vm_map_user_range_large_file", &range, &range_sz, NULL, 0);
102*4f1223e8SApple OSS Distributions 		T_QUIET;
103*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "successfully retrieved user large file range");
104*4f1223e8SApple OSS Distributions 		break;
105*4f1223e8SApple OSS Distributions 
106*4f1223e8SApple OSS Distributions 	default:
107*4f1223e8SApple OSS Distributions 		/* Fall through with EINVAL */
108*4f1223e8SApple OSS Distributions 		break;
109*4f1223e8SApple OSS Distributions 	}
110*4f1223e8SApple OSS Distributions 
111*4f1223e8SApple OSS Distributions 	return range;
112*4f1223e8SApple OSS Distributions }
113*4f1223e8SApple OSS Distributions 
114*4f1223e8SApple OSS Distributions static task_vm_info_data_t
get_vm_task_info(void)115*4f1223e8SApple OSS Distributions get_vm_task_info(void)
116*4f1223e8SApple OSS Distributions {
117*4f1223e8SApple OSS Distributions 	task_vm_info_data_t ti;
118*4f1223e8SApple OSS Distributions 
119*4f1223e8SApple OSS Distributions 	mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
120*4f1223e8SApple OSS Distributions 	kern_return_t const kr = task_info(mach_task_self(),
121*4f1223e8SApple OSS Distributions 	    TASK_VM_INFO,
122*4f1223e8SApple OSS Distributions 	    (task_info_t) &ti,
123*4f1223e8SApple OSS Distributions 	    &count);
124*4f1223e8SApple OSS Distributions 	T_QUIET;
125*4f1223e8SApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "get task_info()");
126*4f1223e8SApple OSS Distributions 	return ti;
127*4f1223e8SApple OSS Distributions }
128*4f1223e8SApple OSS Distributions 
129*4f1223e8SApple OSS Distributions static mach_vm_address_t
assert_allocate(mach_vm_address_t dst,int vm_flags)130*4f1223e8SApple OSS Distributions assert_allocate(mach_vm_address_t dst, int vm_flags)
131*4f1223e8SApple OSS Distributions {
132*4f1223e8SApple OSS Distributions 	int ret = mach_vm_allocate(mach_task_self(), &dst, ALLOCATION_SIZE, vm_flags);
133*4f1223e8SApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(ret, "vm_allocate");
134*4f1223e8SApple OSS Distributions 	return dst;
135*4f1223e8SApple OSS Distributions }
136*4f1223e8SApple OSS Distributions 
137*4f1223e8SApple OSS Distributions static void
assert_in_range(struct mach_vm_range range,mach_vm_offset_t addr)138*4f1223e8SApple OSS Distributions assert_in_range(struct mach_vm_range range, mach_vm_offset_t addr)
139*4f1223e8SApple OSS Distributions {
140*4f1223e8SApple OSS Distributions 	T_LOG("checking if %llx <= %llx <= %llx", range.min_address, addr,
141*4f1223e8SApple OSS Distributions 	    range.max_address);
142*4f1223e8SApple OSS Distributions 	T_EXPECT_GE(addr, range.min_address, "allocation above min address");
143*4f1223e8SApple OSS Distributions 	T_EXPECT_LE(addr, range.max_address, "allocation below max address");
144*4f1223e8SApple OSS Distributions }
145*4f1223e8SApple OSS Distributions 
146*4f1223e8SApple OSS Distributions static void
assert_in_heap_range(mach_vm_offset_t addr)147*4f1223e8SApple OSS Distributions assert_in_heap_range(mach_vm_offset_t addr)
148*4f1223e8SApple OSS Distributions {
149*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
150*4f1223e8SApple OSS Distributions 
151*4f1223e8SApple OSS Distributions 	assert_in_range(range, addr);
152*4f1223e8SApple OSS Distributions }
153*4f1223e8SApple OSS Distributions 
154*4f1223e8SApple OSS Distributions static void *
assert_mmap(void * addr,size_t sz,int fd,int flags)155*4f1223e8SApple OSS Distributions assert_mmap(void *addr, size_t sz, int fd, int flags)
156*4f1223e8SApple OSS Distributions {
157*4f1223e8SApple OSS Distributions 	void *ret = mmap(addr, sz, VM_PROT_READ | VM_PROT_WRITE,
158*4f1223e8SApple OSS Distributions 	    flags, fd, 0);
159*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(ret, MAP_FAILED, "mmap should not have MAP_FAILED");
160*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(ret, NULL, "mmap should have returned a valid pointer");
161*4f1223e8SApple OSS Distributions 	return ret;
162*4f1223e8SApple OSS Distributions }
163*4f1223e8SApple OSS Distributions 
164*4f1223e8SApple OSS Distributions static void
assert_allocate_eq(mach_vm_address_t dst,int vm_flags)165*4f1223e8SApple OSS Distributions assert_allocate_eq(mach_vm_address_t dst, int vm_flags)
166*4f1223e8SApple OSS Distributions {
167*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = dst;
168*4f1223e8SApple OSS Distributions 
169*4f1223e8SApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(mach_vm_allocate(mach_task_self(), &target,
170*4f1223e8SApple OSS Distributions 	    ALLOCATION_SIZE, vm_flags), "vm_allocate");
171*4f1223e8SApple OSS Distributions 
172*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(target, dst, "target/dst differ");
173*4f1223e8SApple OSS Distributions }
174*4f1223e8SApple OSS Distributions 
175*4f1223e8SApple OSS Distributions static mach_vm_address_t
assert_allocate_in_range(int target_range,mach_vm_address_t dst,int vm_flags)176*4f1223e8SApple OSS Distributions assert_allocate_in_range(int target_range, mach_vm_address_t dst, int vm_flags)
177*4f1223e8SApple OSS Distributions {
178*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(target_range);
179*4f1223e8SApple OSS Distributions 	dst = assert_allocate(dst, vm_flags);
180*4f1223e8SApple OSS Distributions 
181*4f1223e8SApple OSS Distributions 	assert_in_range(range, (mach_vm_offset_t)dst);
182*4f1223e8SApple OSS Distributions 
183*4f1223e8SApple OSS Distributions 	return dst;
184*4f1223e8SApple OSS Distributions }
185*4f1223e8SApple OSS Distributions 
186*4f1223e8SApple OSS Distributions static void *
assert_mmap_in_range(void * addr,int target_range,size_t sz,int fd,int flags)187*4f1223e8SApple OSS Distributions assert_mmap_in_range(void *addr, int target_range, size_t sz, int fd, int flags)
188*4f1223e8SApple OSS Distributions {
189*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(target_range);
190*4f1223e8SApple OSS Distributions 	void *dst = assert_mmap(addr, sz, fd, flags);
191*4f1223e8SApple OSS Distributions 
192*4f1223e8SApple OSS Distributions 	assert_in_range(range, (mach_vm_offset_t)dst);
193*4f1223e8SApple OSS Distributions 
194*4f1223e8SApple OSS Distributions 	return dst;
195*4f1223e8SApple OSS Distributions }
196*4f1223e8SApple OSS Distributions 
197*4f1223e8SApple OSS Distributions static void
ensure_mmap_fails(void * addr,size_t sz,int flags,int fd)198*4f1223e8SApple OSS Distributions ensure_mmap_fails(void *addr, size_t sz, int flags, int fd)
199*4f1223e8SApple OSS Distributions {
200*4f1223e8SApple OSS Distributions 	void *ret = mmap(addr, sz, VM_PROT_READ | VM_PROT_WRITE, flags, fd, 0);
201*4f1223e8SApple OSS Distributions 	T_QUIET;
202*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ_PTR(ret, MAP_FAILED, "mmap should fail");
203*4f1223e8SApple OSS Distributions }
204*4f1223e8SApple OSS Distributions 
205*4f1223e8SApple OSS Distributions __attribute__((overloadable))
206*4f1223e8SApple OSS Distributions static void
207*4f1223e8SApple OSS Distributions fork_child_test(void (^child_test)(void))
208*4f1223e8SApple OSS Distributions {
209*4f1223e8SApple OSS Distributions 	pid_t child_pid;
210*4f1223e8SApple OSS Distributions 	int err;
211*4f1223e8SApple OSS Distributions 
212*4f1223e8SApple OSS Distributions 	child_pid = fork();
213*4f1223e8SApple OSS Distributions 
214*4f1223e8SApple OSS Distributions 	if (child_pid == 0) {
215*4f1223e8SApple OSS Distributions 		/* child process */
216*4f1223e8SApple OSS Distributions 		T_LOG("in child");
217*4f1223e8SApple OSS Distributions 		child_test();
218*4f1223e8SApple OSS Distributions 		exit(0);
219*4f1223e8SApple OSS Distributions 	} else {
220*4f1223e8SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(child_pid, "fork process");
221*4f1223e8SApple OSS Distributions 
222*4f1223e8SApple OSS Distributions 		/* wait for child process to exit */
223*4f1223e8SApple OSS Distributions 		if (dt_waitpid(child_pid, &err, NULL, 30) == false) {
224*4f1223e8SApple OSS Distributions 			T_FAIL("dt_waitpid() failed on child pid %d", child_pid);
225*4f1223e8SApple OSS Distributions 		}
226*4f1223e8SApple OSS Distributions 	}
227*4f1223e8SApple OSS Distributions }
228*4f1223e8SApple OSS Distributions 
229*4f1223e8SApple OSS Distributions __attribute__((overloadable))
230*4f1223e8SApple OSS Distributions static void
fork_child_test(void (* child_test)(void))231*4f1223e8SApple OSS Distributions fork_child_test(void (*child_test)(void))
232*4f1223e8SApple OSS Distributions {
233*4f1223e8SApple OSS Distributions 	fork_child_test(^{
234*4f1223e8SApple OSS Distributions 		child_test();
235*4f1223e8SApple OSS Distributions 	});
236*4f1223e8SApple OSS Distributions }
237*4f1223e8SApple OSS Distributions 
238*4f1223e8SApple OSS Distributions static void
cleanup_file(void)239*4f1223e8SApple OSS Distributions cleanup_file(void)
240*4f1223e8SApple OSS Distributions {
241*4f1223e8SApple OSS Distributions 	unlink(_filepath);
242*4f1223e8SApple OSS Distributions 	bzero(_filepath, MAXPATHLEN);
243*4f1223e8SApple OSS Distributions }
244*4f1223e8SApple OSS Distributions 
245*4f1223e8SApple OSS Distributions T_DECL(range_allocate_heap,
246*4f1223e8SApple OSS Distributions     "ensure malloc tagged memory is allocated within the heap range", T_META_TAG_VM_PREFERRED)
247*4f1223e8SApple OSS Distributions {
248*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
249*4f1223e8SApple OSS Distributions 
250*4f1223e8SApple OSS Distributions 	assert_allocate_in_range(HEAP, 0, RANGE_HEAP_FLAGS);
251*4f1223e8SApple OSS Distributions }
252*4f1223e8SApple OSS Distributions 
253*4f1223e8SApple OSS Distributions T_DECL(range_allocate_anywhere,
254*4f1223e8SApple OSS Distributions     "ensure allocation is within target range when hint is outwith range", T_META_TAG_VM_PREFERRED)
255*4f1223e8SApple OSS Distributions {
256*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
257*4f1223e8SApple OSS Distributions 
258*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
259*4f1223e8SApple OSS Distributions 
260*4f1223e8SApple OSS Distributions 	assert_allocate_in_range(HEAP, range.min_address - ALLOCATION_SIZE, RANGE_HEAP_FLAGS);
261*4f1223e8SApple OSS Distributions }
262*4f1223e8SApple OSS Distributions 
263*4f1223e8SApple OSS Distributions T_DECL(range_allocate_stack,
264*4f1223e8SApple OSS Distributions     "ensure a stack allocation is in the default range", T_META_TAG_VM_PREFERRED)
265*4f1223e8SApple OSS Distributions {
266*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
267*4f1223e8SApple OSS Distributions 
268*4f1223e8SApple OSS Distributions 	assert_allocate_in_range(DEFAULT, 0, RANGE_DEFAULT_FLAGS);
269*4f1223e8SApple OSS Distributions }
270*4f1223e8SApple OSS Distributions 
271*4f1223e8SApple OSS Distributions static void
ensure_fixed_mappings_succeed_cross(int heap)272*4f1223e8SApple OSS Distributions ensure_fixed_mappings_succeed_cross(int heap)
273*4f1223e8SApple OSS Distributions {
274*4f1223e8SApple OSS Distributions 	vm_map_address_t addr;
275*4f1223e8SApple OSS Distributions 
276*4f1223e8SApple OSS Distributions 	addr = assert_allocate(0, VM_FLAGS_ANYWHERE | heap);
277*4f1223e8SApple OSS Distributions 	vm_deallocate(mach_task_self(), addr, ALLOCATION_SIZE);
278*4f1223e8SApple OSS Distributions 
279*4f1223e8SApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_MEMORY_RANGE_DEFAULT);
280*4f1223e8SApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MEMORY_RANGE_DEFAULT);
281*4f1223e8SApple OSS Distributions 	vm_deallocate(mach_task_self(), addr, ALLOCATION_SIZE);
282*4f1223e8SApple OSS Distributions 
283*4f1223e8SApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_MEMORY_RANGE_HEAP);
284*4f1223e8SApple OSS Distributions 	assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MEMORY_RANGE_HEAP);
285*4f1223e8SApple OSS Distributions 	vm_deallocate(mach_task_self(), addr, ALLOCATION_SIZE);
286*4f1223e8SApple OSS Distributions }
287*4f1223e8SApple OSS Distributions 
288*4f1223e8SApple OSS Distributions static void
ensure_rogue_fixed_fails(void)289*4f1223e8SApple OSS Distributions ensure_rogue_fixed_fails(void)
290*4f1223e8SApple OSS Distributions {
291*4f1223e8SApple OSS Distributions 	struct mach_vm_range def = get_range(DEFAULT);
292*4f1223e8SApple OSS Distributions 	struct mach_vm_range heap = get_range(HEAP);
293*4f1223e8SApple OSS Distributions 	mach_vm_address_t addr;
294*4f1223e8SApple OSS Distributions 	kern_return_t kr;
295*4f1223e8SApple OSS Distributions 
296*4f1223e8SApple OSS Distributions 	if (def.max_address + 3 * ALLOCATION_SIZE <= heap.min_address) {
297*4f1223e8SApple OSS Distributions 		addr = heap.min_address - 2 * ALLOCATION_SIZE;
298*4f1223e8SApple OSS Distributions 	} else {
299*4f1223e8SApple OSS Distributions 		/*
300*4f1223e8SApple OSS Distributions 		 * in the unlikely event when there's no space
301*4f1223e8SApple OSS Distributions 		 * between default and heap, then there must be
302*4f1223e8SApple OSS Distributions 		 * a hole after heap.
303*4f1223e8SApple OSS Distributions 		 */
304*4f1223e8SApple OSS Distributions 		addr = heap.max_address + ALLOCATION_SIZE;
305*4f1223e8SApple OSS Distributions 	}
306*4f1223e8SApple OSS Distributions 
307*4f1223e8SApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &addr,
308*4f1223e8SApple OSS Distributions 	    ALLOCATION_SIZE, VM_FLAGS_FIXED);
309*4f1223e8SApple OSS Distributions 	T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ADDRESS, "should fail");
310*4f1223e8SApple OSS Distributions }
311*4f1223e8SApple OSS Distributions 
312*4f1223e8SApple OSS Distributions static void
ensure_fixed_mapping(void)313*4f1223e8SApple OSS Distributions ensure_fixed_mapping(void)
314*4f1223e8SApple OSS Distributions {
315*4f1223e8SApple OSS Distributions 	ensure_fixed_mappings_succeed_cross(VM_MEMORY_RANGE_DEFAULT);
316*4f1223e8SApple OSS Distributions 	ensure_fixed_mappings_succeed_cross(VM_MEMORY_RANGE_HEAP);
317*4f1223e8SApple OSS Distributions 
318*4f1223e8SApple OSS Distributions 	ensure_rogue_fixed_fails();
319*4f1223e8SApple OSS Distributions }
320*4f1223e8SApple OSS Distributions 
321*4f1223e8SApple OSS Distributions T_DECL(range_allocate_fixed, "ensure fixed target is honored (even with an incorrect tag)", T_META_TAG_VM_PREFERRED)
322*4f1223e8SApple OSS Distributions {
323*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
324*4f1223e8SApple OSS Distributions 
325*4f1223e8SApple OSS Distributions 	ensure_fixed_mapping();
326*4f1223e8SApple OSS Distributions 	fork_child_test(ensure_fixed_mapping);
327*4f1223e8SApple OSS Distributions }
328*4f1223e8SApple OSS Distributions 
329*4f1223e8SApple OSS Distributions T_DECL(range_mmap_anon, "ensure anon mapping within HEAP range", T_META_TAG_VM_PREFERRED)
330*4f1223e8SApple OSS Distributions {
331*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
332*4f1223e8SApple OSS Distributions 
333*4f1223e8SApple OSS Distributions 	assert_mmap_in_range(NULL, HEAP, ALLOCATION_SIZE, -1, MAP_ANON | MAP_PRIVATE);
334*4f1223e8SApple OSS Distributions }
335*4f1223e8SApple OSS Distributions 
336*4f1223e8SApple OSS Distributions T_DECL(range_mmap_file, "ensure file is mapped within HEAP range", T_META_TAG_VM_PREFERRED)
337*4f1223e8SApple OSS Distributions {
338*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
339*4f1223e8SApple OSS Distributions 
340*4f1223e8SApple OSS Distributions 	int fd = -1;
341*4f1223e8SApple OSS Distributions 
342*4f1223e8SApple OSS Distributions 	/* prepare temp file */
343*4f1223e8SApple OSS Distributions 	strncpy(_filepath, "/tmp/mapfile.XXXXXX", MAXPATHLEN);
344*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(fd = mkstemp(_filepath), NULL);
345*4f1223e8SApple OSS Distributions 	atexit(cleanup_file);
346*4f1223e8SApple OSS Distributions 
347*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ftruncate(fd, (off_t)ALLOCATION_SIZE), NULL);
348*4f1223e8SApple OSS Distributions 
349*4f1223e8SApple OSS Distributions 	/* map it in to the heap rage */
350*4f1223e8SApple OSS Distributions #if TARGET_OS_OSX
351*4f1223e8SApple OSS Distributions 	T_LOG("mapping file in DEFAULT range");
352*4f1223e8SApple OSS Distributions 	assert_mmap_in_range(NULL, DEFAULT, ALLOCATION_SIZE, fd, MAP_FILE | MAP_SHARED);
353*4f1223e8SApple OSS Distributions #else
354*4f1223e8SApple OSS Distributions 	T_LOG("mapping file in HEAP range");
355*4f1223e8SApple OSS Distributions 	assert_mmap_in_range(NULL, HEAP, ALLOCATION_SIZE, fd, MAP_FILE | MAP_SHARED);
356*4f1223e8SApple OSS Distributions #endif
357*4f1223e8SApple OSS Distributions }
358*4f1223e8SApple OSS Distributions 
359*4f1223e8SApple OSS Distributions 
360*4f1223e8SApple OSS Distributions T_DECL(range_mmap_alias_tag, "ensure anon mapping with tag is honored", T_META_TAG_VM_PREFERRED)
361*4f1223e8SApple OSS Distributions {
362*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
363*4f1223e8SApple OSS Distributions 
364*4f1223e8SApple OSS Distributions 	assert_mmap_in_range(NULL, DEFAULT, ALLOCATION_SIZE, VM_MEMORY_RANGE_DEFAULT, MAP_ANON | MAP_PRIVATE);
365*4f1223e8SApple OSS Distributions }
366*4f1223e8SApple OSS Distributions 
367*4f1223e8SApple OSS Distributions T_DECL(range_mmap_with_low_hint,
368*4f1223e8SApple OSS Distributions     "ensure allocation is within target range when hint is below range", T_META_TAG_VM_PREFERRED)
369*4f1223e8SApple OSS Distributions {
370*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
371*4f1223e8SApple OSS Distributions 
372*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
373*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = range.min_address - ALLOCATION_SIZE;
374*4f1223e8SApple OSS Distributions 
375*4f1223e8SApple OSS Distributions 	assert_mmap_in_range((void *)target, HEAP, ALLOCATION_SIZE, -1, MAP_ANON | MAP_PRIVATE);
376*4f1223e8SApple OSS Distributions }
377*4f1223e8SApple OSS Distributions 
378*4f1223e8SApple OSS Distributions T_DECL(range_mmap_with_high_hint,
379*4f1223e8SApple OSS Distributions     "ensure allocation is within target range when hint is within range", T_META_TAG_VM_PREFERRED)
380*4f1223e8SApple OSS Distributions {
381*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
382*4f1223e8SApple OSS Distributions 
383*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
384*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = range.max_address - 100 * ALLOCATION_SIZE;
385*4f1223e8SApple OSS Distributions 
386*4f1223e8SApple OSS Distributions 	void *dst = assert_mmap_in_range((void *)target, HEAP, ALLOCATION_SIZE, -1, MAP_ANON | MAP_PRIVATE);
387*4f1223e8SApple OSS Distributions 
388*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ((mach_vm_address_t)dst, target, "unexpected allocation address");
389*4f1223e8SApple OSS Distributions }
390*4f1223e8SApple OSS Distributions 
391*4f1223e8SApple OSS Distributions T_DECL(range_mmap_with_bad_hint,
392*4f1223e8SApple OSS Distributions     "ensure allocation fails when hint is above range", T_META_TAG_VM_PREFERRED)
393*4f1223e8SApple OSS Distributions {
394*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
395*4f1223e8SApple OSS Distributions 
396*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
397*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = range.max_address + 0x100000000;
398*4f1223e8SApple OSS Distributions 
399*4f1223e8SApple OSS Distributions 	/* mmap should retry with 0 base on initial KERN_NO_SPACE failure */
400*4f1223e8SApple OSS Distributions 	assert_mmap_in_range((void *)target, HEAP, ALLOCATION_SIZE, -1, MAP_ANON | MAP_PRIVATE);
401*4f1223e8SApple OSS Distributions }
402*4f1223e8SApple OSS Distributions 
403*4f1223e8SApple OSS Distributions T_DECL(range_mach_vm_map_with_bad_hint,
404*4f1223e8SApple OSS Distributions     "ensure mach_vm_map fails when hint is above range", T_META_TAG_VM_PREFERRED)
405*4f1223e8SApple OSS Distributions {
406*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
407*4f1223e8SApple OSS Distributions 
408*4f1223e8SApple OSS Distributions 	struct mach_vm_range range = get_range(HEAP);
409*4f1223e8SApple OSS Distributions 	mach_vm_address_t addr = range.max_address + 0x100000000;
410*4f1223e8SApple OSS Distributions 
411*4f1223e8SApple OSS Distributions 	/*
412*4f1223e8SApple OSS Distributions 	 * unlike mmap & vm_allocate, mach_vm_map should fail when given a hint
413*4f1223e8SApple OSS Distributions 	 * out with the target range.
414*4f1223e8SApple OSS Distributions 	 */
415*4f1223e8SApple OSS Distributions 	int ret = mach_vm_map(mach_task_self(), &addr, ALLOCATION_SIZE,
416*4f1223e8SApple OSS Distributions 	    (mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, MACH_PORT_NULL,
417*4f1223e8SApple OSS Distributions 	    (memory_object_offset_t)0, FALSE, VM_PROT_DEFAULT, VM_PROT_ALL,
418*4f1223e8SApple OSS Distributions 	    VM_INHERIT_DEFAULT);
419*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(ret, KERN_NO_SPACE, "expected KERN_NO_SPACE");
420*4f1223e8SApple OSS Distributions }
421*4f1223e8SApple OSS Distributions 
422*4f1223e8SApple OSS Distributions T_DECL(range_mach_vm_remap_default,
423*4f1223e8SApple OSS Distributions     "ensure mach_vm_remap is successful in default range", T_META_TAG_VM_PREFERRED)
424*4f1223e8SApple OSS Distributions {
425*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
426*4f1223e8SApple OSS Distributions 
427*4f1223e8SApple OSS Distributions 	vm_prot_t curprot;
428*4f1223e8SApple OSS Distributions 	vm_prot_t maxprot;
429*4f1223e8SApple OSS Distributions 
430*4f1223e8SApple OSS Distributions 	mach_vm_address_t addr = assert_allocate_in_range(DEFAULT, 0, RANGE_DEFAULT_FLAGS);
431*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = addr + ALLOCATION_SIZE;
432*4f1223e8SApple OSS Distributions 
433*4f1223e8SApple OSS Distributions 	int ret = mach_vm_remap(mach_task_self(), &target, ALLOCATION_SIZE,
434*4f1223e8SApple OSS Distributions 	    (mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, mach_task_self(),
435*4f1223e8SApple OSS Distributions 	    addr, FALSE, &curprot, &maxprot, VM_INHERIT_NONE);
436*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(ret, KERN_SUCCESS, "expected KERN_SUCCESS");
437*4f1223e8SApple OSS Distributions }
438*4f1223e8SApple OSS Distributions 
439*4f1223e8SApple OSS Distributions T_DECL(range_mach_vm_remap_heap_with_hint,
440*4f1223e8SApple OSS Distributions     "ensure mach_vm_remap is successful in heap range", T_META_TAG_VM_PREFERRED)
441*4f1223e8SApple OSS Distributions {
442*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
443*4f1223e8SApple OSS Distributions 
444*4f1223e8SApple OSS Distributions 	vm_prot_t curprot;
445*4f1223e8SApple OSS Distributions 	vm_prot_t maxprot;
446*4f1223e8SApple OSS Distributions 
447*4f1223e8SApple OSS Distributions 	mach_vm_address_t addr = assert_allocate_in_range(HEAP, 0, RANGE_HEAP_FLAGS);
448*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = addr + ALLOCATION_SIZE;
449*4f1223e8SApple OSS Distributions 
450*4f1223e8SApple OSS Distributions 	int ret = mach_vm_remap(mach_task_self(), &target, ALLOCATION_SIZE,
451*4f1223e8SApple OSS Distributions 	    (mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, mach_task_self(),
452*4f1223e8SApple OSS Distributions 	    addr, FALSE, &curprot, &maxprot, VM_INHERIT_NONE);
453*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(ret, KERN_SUCCESS, "expected KERN_SUCCESS");
454*4f1223e8SApple OSS Distributions 	assert_in_heap_range(target);
455*4f1223e8SApple OSS Distributions }
456*4f1223e8SApple OSS Distributions 
457*4f1223e8SApple OSS Distributions T_DECL(range_mach_vm_remap_heap,
458*4f1223e8SApple OSS Distributions     "ensure mach_vm_remap remains in same range", T_META_TAG_VM_PREFERRED)
459*4f1223e8SApple OSS Distributions {
460*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
461*4f1223e8SApple OSS Distributions 
462*4f1223e8SApple OSS Distributions 	vm_prot_t curprot;
463*4f1223e8SApple OSS Distributions 	vm_prot_t maxprot;
464*4f1223e8SApple OSS Distributions 
465*4f1223e8SApple OSS Distributions 	mach_vm_address_t addr = assert_allocate_in_range(HEAP, 0, RANGE_HEAP_FLAGS);
466*4f1223e8SApple OSS Distributions 	mach_vm_address_t target = 0;
467*4f1223e8SApple OSS Distributions 
468*4f1223e8SApple OSS Distributions 	int ret = mach_vm_remap(mach_task_self(), &target, ALLOCATION_SIZE,
469*4f1223e8SApple OSS Distributions 	    (mach_vm_offset_t)0, VM_FLAGS_ANYWHERE, mach_task_self(),
470*4f1223e8SApple OSS Distributions 	    addr, FALSE, &curprot, &maxprot, VM_INHERIT_NONE);
471*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, KERN_SUCCESS, "expected KERN_SUCCESS");
472*4f1223e8SApple OSS Distributions 	assert_in_heap_range(target);
473*4f1223e8SApple OSS Distributions }
474*4f1223e8SApple OSS Distributions 
475*4f1223e8SApple OSS Distributions static void
ensure_range(void)476*4f1223e8SApple OSS Distributions ensure_range(void)
477*4f1223e8SApple OSS Distributions {
478*4f1223e8SApple OSS Distributions 	struct mach_vm_range def = get_range(DEFAULT);
479*4f1223e8SApple OSS Distributions 	struct mach_vm_range heap = get_range(HEAP);
480*4f1223e8SApple OSS Distributions 
481*4f1223e8SApple OSS Distributions 	T_EXPECT_GT(heap.min_address, def.max_address,
482*4f1223e8SApple OSS Distributions 	    "ranges should not overlap");
483*4f1223e8SApple OSS Distributions 	T_EXPECT_LE(heap.max_address, MACH_VM_MAX_ADDRESS,
484*4f1223e8SApple OSS Distributions 	    "expected max <= %llx", MACH_VM_MAX_ADDRESS);
485*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(heap.min_address,
486*4f1223e8SApple OSS Distributions 	    heap.min_address & (unsigned long)~0x1FFFFF,
487*4f1223e8SApple OSS Distributions 	    "expected alignment on 2MB TT boundary");
488*4f1223e8SApple OSS Distributions }
489*4f1223e8SApple OSS Distributions 
490*4f1223e8SApple OSS Distributions static void
ensure_child_range(void)491*4f1223e8SApple OSS Distributions ensure_child_range(void)
492*4f1223e8SApple OSS Distributions {
493*4f1223e8SApple OSS Distributions 	struct mach_vm_range def = get_range(DEFAULT);
494*4f1223e8SApple OSS Distributions 	struct mach_vm_range heap = get_range(HEAP);
495*4f1223e8SApple OSS Distributions 
496*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(def.min_address, parent_default.min_address,
497*4f1223e8SApple OSS Distributions 	    "expected forked default min to be equal");
498*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(def.max_address, parent_default.max_address,
499*4f1223e8SApple OSS Distributions 	    "expected forked default max to be equal");
500*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(heap.min_address, parent_heap.min_address,
501*4f1223e8SApple OSS Distributions 	    "expected forked heap min to be equal");
502*4f1223e8SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(heap.max_address, parent_heap.max_address,
503*4f1223e8SApple OSS Distributions 	    "expected forked heap max to be equal");
504*4f1223e8SApple OSS Distributions }
505*4f1223e8SApple OSS Distributions 
506*4f1223e8SApple OSS Distributions T_DECL(range_ensure_bounds, "ensure ranges respect map bounds", T_META_TAG_VM_PREFERRED)
507*4f1223e8SApple OSS Distributions {
508*4f1223e8SApple OSS Distributions 	CHECK_RANGES_ENABLED();
509*4f1223e8SApple OSS Distributions 
510*4f1223e8SApple OSS Distributions 	parent_default = get_range(DEFAULT);
511*4f1223e8SApple OSS Distributions 	parent_heap = get_range(HEAP);
512*4f1223e8SApple OSS Distributions 
513*4f1223e8SApple OSS Distributions 	ensure_range();
514*4f1223e8SApple OSS Distributions 
515*4f1223e8SApple OSS Distributions 	for (uint32_t i = 0; i < CHILD_PROCESS_COUNT; i++) {
516*4f1223e8SApple OSS Distributions 		fork_child_test(ensure_child_range);
517*4f1223e8SApple OSS Distributions 	}
518*4f1223e8SApple OSS Distributions }
519*4f1223e8SApple OSS Distributions 
520*4f1223e8SApple OSS Distributions static bool
parse_void_ranges(struct mach_vm_range * void1,struct mach_vm_range * void2)521*4f1223e8SApple OSS Distributions parse_void_ranges(struct mach_vm_range *void1, struct mach_vm_range *void2)
522*4f1223e8SApple OSS Distributions {
523*4f1223e8SApple OSS Distributions 	char buf[256];
524*4f1223e8SApple OSS Distributions 	size_t bsz = sizeof(buf) - 1;
525*4f1223e8SApple OSS Distributions 	char *s;
526*4f1223e8SApple OSS Distributions 
527*4f1223e8SApple OSS Distributions 	if (sysctlbyname("vm.malloc_ranges", buf, &bsz, NULL, 0) == -1) {
528*4f1223e8SApple OSS Distributions 		if (errno == ENOENT) {
529*4f1223e8SApple OSS Distributions 			return false;
530*4f1223e8SApple OSS Distributions 		}
531*4f1223e8SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(-1, "sysctlbyname(vm.malloc_ranges)");
532*4f1223e8SApple OSS Distributions 	}
533*4f1223e8SApple OSS Distributions 	buf[bsz] = '\0';
534*4f1223e8SApple OSS Distributions 
535*4f1223e8SApple OSS Distributions 	s = buf;
536*4f1223e8SApple OSS Distributions 
537*4f1223e8SApple OSS Distributions 	void1->min_address = strtoull(s, &s, 16);
538*4f1223e8SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(*s, ':', "should have a ':'");
539*4f1223e8SApple OSS Distributions 	s++;
540*4f1223e8SApple OSS Distributions 
541*4f1223e8SApple OSS Distributions 	void1->max_address = strtoull(s, &s, 16);
542*4f1223e8SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(*s, ' ', "should have a ' '");
543*4f1223e8SApple OSS Distributions 	s++;
544*4f1223e8SApple OSS Distributions 
545*4f1223e8SApple OSS Distributions 	void2->min_address = strtoull(s, &s, 16);
546*4f1223e8SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(*s, ':', "should have a ':'");
547*4f1223e8SApple OSS Distributions 	s++;
548*4f1223e8SApple OSS Distributions 
549*4f1223e8SApple OSS Distributions 	void2->max_address = strtoull(s, &s, 16);
550*4f1223e8SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(*s, '\0', "should be done");
551*4f1223e8SApple OSS Distributions 
552*4f1223e8SApple OSS Distributions 	return true;
553*4f1223e8SApple OSS Distributions }
554*4f1223e8SApple OSS Distributions 
555*4f1223e8SApple OSS Distributions T_DECL(create_range, "ensure create ranges kinda works", T_META_TAG_VM_PREFERRED)
556*4f1223e8SApple OSS Distributions {
557*4f1223e8SApple OSS Distributions 	struct mach_vm_range void1, void2, *r;
558*4f1223e8SApple OSS Distributions 
559*4f1223e8SApple OSS Distributions 	mach_vm_range_recipe_v1_t array[10];
560*4f1223e8SApple OSS Distributions 	uint32_t nranges = 0;
561*4f1223e8SApple OSS Distributions 
562*4f1223e8SApple OSS Distributions 	if (!parse_void_ranges(&void1, &void2)) {
563*4f1223e8SApple OSS Distributions 		T_SKIP("malloc_ranges not supported");
564*4f1223e8SApple OSS Distributions 	}
565*4f1223e8SApple OSS Distributions 
566*4f1223e8SApple OSS Distributions 	T_LOG("Ranges are %#llx:%#llx %#llx:%#llx",
567*4f1223e8SApple OSS Distributions 	    void1.min_address, void1.max_address,
568*4f1223e8SApple OSS Distributions 	    void2.min_address, void2.max_address);
569*4f1223e8SApple OSS Distributions 
570*4f1223e8SApple OSS Distributions #define reset() \
571*4f1223e8SApple OSS Distributions 	nranges = 0
572*4f1223e8SApple OSS Distributions #define add_range(l, r) \
573*4f1223e8SApple OSS Distributions 	array[nranges++] = (mach_vm_range_recipe_v1_t){ \
574*4f1223e8SApple OSS Distributions 	    .range = { l, r }, .range_tag = MACH_VM_RANGE_FIXED, \
575*4f1223e8SApple OSS Distributions 	}
576*4f1223e8SApple OSS Distributions #define create_ranges() \
577*4f1223e8SApple OSS Distributions 	mach_vm_range_create(mach_task_self(), MACH_VM_RANGE_FLAVOR_V1, \
578*4f1223e8SApple OSS Distributions 	    (mach_vm_range_recipes_raw_t)array, sizeof(array[0]) * nranges)
579*4f1223e8SApple OSS Distributions 
580*4f1223e8SApple OSS Distributions 	if (void1.min_address + MiB(128) > void1.max_address) {
581*4f1223e8SApple OSS Distributions 		r = &void2;
582*4f1223e8SApple OSS Distributions 	} else {
583*4f1223e8SApple OSS Distributions 		r = &void1;
584*4f1223e8SApple OSS Distributions 	}
585*4f1223e8SApple OSS Distributions 
586*4f1223e8SApple OSS Distributions 	reset();
587*4f1223e8SApple OSS Distributions 	add_range(void1.min_address - MiB(10), void1.min_address);
588*4f1223e8SApple OSS Distributions 	T_EXPECT_MACH_ERROR(create_ranges(), KERN_INVALID_ARGUMENT,
589*4f1223e8SApple OSS Distributions 	    "should fail: range outside of voids");
590*4f1223e8SApple OSS Distributions 
591*4f1223e8SApple OSS Distributions 	reset();
592*4f1223e8SApple OSS Distributions 	add_range(r->min_address + MiB(1), r->min_address + MiB(3));
593*4f1223e8SApple OSS Distributions 	add_range(r->min_address, r->min_address + MiB(2));
594*4f1223e8SApple OSS Distributions 	T_EXPECT_MACH_ERROR(create_ranges(), KERN_INVALID_ARGUMENT,
595*4f1223e8SApple OSS Distributions 	    "should fail: overlapping ranges");
596*4f1223e8SApple OSS Distributions 
597*4f1223e8SApple OSS Distributions 	reset();
598*4f1223e8SApple OSS Distributions 	add_range(r->min_address, r->min_address + MiB(1));
599*4f1223e8SApple OSS Distributions 	add_range(r->min_address + MiB(2), r->min_address + MiB(3));
600*4f1223e8SApple OSS Distributions 	T_EXPECT_MACH_SUCCESS(create_ranges(), "should succeed");
601*4f1223e8SApple OSS Distributions 
602*4f1223e8SApple OSS Distributions 	reset();
603*4f1223e8SApple OSS Distributions 	add_range(r->min_address, r->min_address + MiB(1));
604*4f1223e8SApple OSS Distributions 	add_range(r->min_address + MiB(2), r->min_address + MiB(3));
605*4f1223e8SApple OSS Distributions 	T_EXPECT_MACH_ERROR(create_ranges(), KERN_MEMORY_PRESENT,
606*4f1223e8SApple OSS Distributions 	    "should fail: already allocated");
607*4f1223e8SApple OSS Distributions 
608*4f1223e8SApple OSS Distributions 	reset();
609*4f1223e8SApple OSS Distributions 	add_range(r->min_address + MiB(4), r->min_address + MiB(5));
610*4f1223e8SApple OSS Distributions 	add_range(r->min_address + MiB(6), r->min_address + MiB(7));
611*4f1223e8SApple OSS Distributions 	T_EXPECT_MACH_SUCCESS(create_ranges(), "should succeed");
612*4f1223e8SApple OSS Distributions 
613*4f1223e8SApple OSS Distributions 	__block vm_offset_t offs = 0;
614*4f1223e8SApple OSS Distributions 
615*4f1223e8SApple OSS Distributions 	void (^check_works)(void) = ^{
616*4f1223e8SApple OSS Distributions 		mach_vm_address_t addr;
617*4f1223e8SApple OSS Distributions 		kern_return_t kr;
618*4f1223e8SApple OSS Distributions 
619*4f1223e8SApple OSS Distributions 		offs += PAGE_SIZE;
620*4f1223e8SApple OSS Distributions 		addr  = r->min_address + offs;
621*4f1223e8SApple OSS Distributions 		assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
622*4f1223e8SApple OSS Distributions 
623*4f1223e8SApple OSS Distributions 		addr  = r->min_address + MiB(2) + offs;
624*4f1223e8SApple OSS Distributions 		assert_allocate_eq(addr, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
625*4f1223e8SApple OSS Distributions 
626*4f1223e8SApple OSS Distributions 		addr  = r->min_address + MiB(1);
627*4f1223e8SApple OSS Distributions 		kr = mach_vm_allocate(mach_task_self(), &addr, ALLOCATION_SIZE,
628*4f1223e8SApple OSS Distributions 		    VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
629*4f1223e8SApple OSS Distributions 		T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ADDRESS, "should fail");
630*4f1223e8SApple OSS Distributions 	};
631*4f1223e8SApple OSS Distributions 
632*4f1223e8SApple OSS Distributions 	check_works();
633*4f1223e8SApple OSS Distributions 	fork_child_test(check_works);
634*4f1223e8SApple OSS Distributions 
635*4f1223e8SApple OSS Distributions #undef create_ranges
636*4f1223e8SApple OSS Distributions #undef add_range
637*4f1223e8SApple OSS Distributions #undef reset
638*4f1223e8SApple OSS Distributions }
639*4f1223e8SApple OSS Distributions 
640*4f1223e8SApple OSS Distributions T_DECL(range_mmap_too_large, "ensure mmap fails when allocation is too large", T_META_TAG_VM_PREFERRED)
641*4f1223e8SApple OSS Distributions {
642*4f1223e8SApple OSS Distributions 	// Get VM map min_offset and max_offset
643*4f1223e8SApple OSS Distributions 	task_vm_info_data_t const ti = get_vm_task_info();
644*4f1223e8SApple OSS Distributions 	T_LOG("task_info range: 0x%llx-0x%llx, covering %llu bytes of memory",
645*4f1223e8SApple OSS Distributions 	    ti.min_address, ti.max_address, ti.max_address - ti.min_address);
646*4f1223e8SApple OSS Distributions 
647*4f1223e8SApple OSS Distributions 	// Try to mmap more memory than the address space can handle
648*4f1223e8SApple OSS Distributions 	size_t const sz_too_large = ti.max_address - ti.min_address + 1;
649*4f1223e8SApple OSS Distributions 	T_LOG("Trying to allocate %zu bytes", sz_too_large);
650*4f1223e8SApple OSS Distributions 	ensure_mmap_fails(NULL, sz_too_large, MAP_ANON | MAP_PRIVATE, -1);
651*4f1223e8SApple OSS Distributions }
652*4f1223e8SApple OSS Distributions 
653*4f1223e8SApple OSS Distributions T_DECL(range_mmap_outside_map_range_fixed,
654*4f1223e8SApple OSS Distributions     "ensure mmap fails when making a fixed allocation beyond VM map max address", T_META_TAG_VM_PREFERRED)
655*4f1223e8SApple OSS Distributions {
656*4f1223e8SApple OSS Distributions 	// Get VM map min_offset and max_offset
657*4f1223e8SApple OSS Distributions 	task_vm_info_data_t const ti = get_vm_task_info();
658*4f1223e8SApple OSS Distributions 	T_LOG("task_info range: 0x%llx-0x%llx", ti.min_address, ti.max_address);
659*4f1223e8SApple OSS Distributions 
660*4f1223e8SApple OSS Distributions 	// Try to allocate a page between VM map max_offset and MACH_VM_MAX_ADDRESS
661*4f1223e8SApple OSS Distributions 	mach_vm_address_t const target = ti.max_address + PAGE_SIZE;
662*4f1223e8SApple OSS Distributions 	T_LOG("Trying to allocate memory at 0x%llx", target);
663*4f1223e8SApple OSS Distributions 	ensure_mmap_fails((void *)target, ALLOCATION_SIZE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1);
664*4f1223e8SApple OSS Distributions }
665*4f1223e8SApple OSS Distributions 
666*4f1223e8SApple OSS Distributions static bool
large_file_range_enabled(void)667*4f1223e8SApple OSS Distributions large_file_range_enabled(void)
668*4f1223e8SApple OSS Distributions {
669*4f1223e8SApple OSS Distributions 	struct mach_vm_range range;
670*4f1223e8SApple OSS Distributions 	size_t range_sz = sizeof(range);
671*4f1223e8SApple OSS Distributions 
672*4f1223e8SApple OSS Distributions 	bzero(&range, sizeof(range));
673*4f1223e8SApple OSS Distributions 
674*4f1223e8SApple OSS Distributions 	/*
675*4f1223e8SApple OSS Distributions 	 * We will fail with ENOENT or EINVAL if ranges are either not supported
676*4f1223e8SApple OSS Distributions 	 * or not enabled on our process.
677*4f1223e8SApple OSS Distributions 	 */
678*4f1223e8SApple OSS Distributions 	int const ret = sysctlbyname("vm.vm_map_user_range_large_file",
679*4f1223e8SApple OSS Distributions 	    &range, &range_sz, NULL, 0);
680*4f1223e8SApple OSS Distributions 	if (ret) {
681*4f1223e8SApple OSS Distributions 		T_LOG("vm.vm_map_user_range_large_file errno: %d", errno);
682*4f1223e8SApple OSS Distributions 	} else {
683*4f1223e8SApple OSS Distributions 		T_LOG("large file range: (%llx, %llx)",
684*4f1223e8SApple OSS Distributions 		    range.min_address, range.max_address);
685*4f1223e8SApple OSS Distributions 	}
686*4f1223e8SApple OSS Distributions 	return ret == 0;
687*4f1223e8SApple OSS Distributions }
688*4f1223e8SApple OSS Distributions 
689*4f1223e8SApple OSS Distributions T_DECL(range_mmap_large_file,
690*4f1223e8SApple OSS Distributions     "ensure large file is mapped within LARGE_FILE range", T_META_TAG_VM_PREFERRED)
691*4f1223e8SApple OSS Distributions {
692*4f1223e8SApple OSS Distributions 	if (!large_file_range_enabled()) {
693*4f1223e8SApple OSS Distributions 		T_SKIP("large file range not enabled");
694*4f1223e8SApple OSS Distributions 	}
695*4f1223e8SApple OSS Distributions 
696*4f1223e8SApple OSS Distributions 	void *ptrs[N_ALLOC];
697*4f1223e8SApple OSS Distributions 	uint32_t i;
698*4f1223e8SApple OSS Distributions 
699*4f1223e8SApple OSS Distributions 	int fd = -1;
700*4f1223e8SApple OSS Distributions 	/* prepare temp file */
701*4f1223e8SApple OSS Distributions 	char const * tmp_dir = dt_tmpdir();
702*4f1223e8SApple OSS Distributions 	snprintf(_filepath, MAXPATHLEN, "%s/maplargefile.XXXXXX", tmp_dir);
703*4f1223e8SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(fd = mkstemp(_filepath), NULL);
704*4f1223e8SApple OSS Distributions 	atexit(cleanup_file);
705*4f1223e8SApple OSS Distributions 
706*4f1223e8SApple OSS Distributions 	T_LOG("Attempting to allocate VA space in %llu GB chunks.",
707*4f1223e8SApple OSS Distributions 	    LARGE_ALLOCATION_SIZE);
708*4f1223e8SApple OSS Distributions 	for (i = 0; i < N_ALLOC; ++i) {
709*4f1223e8SApple OSS Distributions 		void *p = assert_mmap_in_range(NULL, LARGE_FILE, LARGE_ALLOCATION_SIZE,
710*4f1223e8SApple OSS Distributions 		    fd, MAP_SHARED | MAP_FILE);
711*4f1223e8SApple OSS Distributions 		if (p == MAP_FAILED) {
712*4f1223e8SApple OSS Distributions 			if (errno != ENOMEM) {
713*4f1223e8SApple OSS Distributions 				T_WITH_ERRNO;
714*4f1223e8SApple OSS Distributions 				T_LOG("mmap failed: stopped at %u of %d/%llu GB chunks",
715*4f1223e8SApple OSS Distributions 				    i + 1, N_ALLOC, LARGE_ALLOCATION_SIZE);
716*4f1223e8SApple OSS Distributions 			}
717*4f1223e8SApple OSS Distributions 			break;
718*4f1223e8SApple OSS Distributions 		} else {
719*4f1223e8SApple OSS Distributions 			T_LOG("allocation %u: %p", i + 1, p);
720*4f1223e8SApple OSS Distributions 		}
721*4f1223e8SApple OSS Distributions 
722*4f1223e8SApple OSS Distributions 		T_QUIET; T_ASSERT_NOTNULL(p, "mmap");
723*4f1223e8SApple OSS Distributions 		ptrs[i] = p;
724*4f1223e8SApple OSS Distributions 	}
725*4f1223e8SApple OSS Distributions 
726*4f1223e8SApple OSS Distributions 	T_EXPECT_GE_UINT(i, N_ALLOC, "Allocate at least %u/%d %llu-GB chunks of VA space",
727*4f1223e8SApple OSS Distributions 	    i, N_ALLOC, (LARGE_ALLOCATION_SIZE / GiB(1)));
728*4f1223e8SApple OSS Distributions 
729*4f1223e8SApple OSS Distributions 	T_LOG("Unmapping memory");
730*4f1223e8SApple OSS Distributions 	for (uint32_t j = 0; j < i; ++j) {
731*4f1223e8SApple OSS Distributions 		int const res = munmap(ptrs[j], LARGE_ALLOCATION_SIZE);
732*4f1223e8SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(res, 0, "munmap");
733*4f1223e8SApple OSS Distributions 	}
734*4f1223e8SApple OSS Distributions }
735