1 #include <darwintest.h>
2 #include <mach/mach.h>
3 #include <mach/mach_vm.h>
4 #include <sys/mman.h>
5 #include <sys/param.h>
6 #include <stdlib.h>
7 #include <fcntl.h>
8
9 extern __typeof__(mmap) __mmap;
10
11 #define N_INTS (32 * 1024)
12 #define N_SIZE (N_INTS * 4)
13
14 static int
make_temp_fd(void)15 make_temp_fd(void)
16 {
17 char path[MAXPATHLEN] = "/tmp/mapfile.XXXXXX";
18 const int batch = 128;
19 int fd;
20
21 T_ASSERT_POSIX_SUCCESS(fd = mkstemp(path), "mkstemp");
22 T_ASSERT_POSIX_SUCCESS(unlink(path), "unlink");
23
24 for (uint32_t i = 1; i <= N_INTS; i += batch) {
25 uint32_t arr[batch];
26
27 for (uint32_t j = 0; j < batch; j++) {
28 arr[j] = i + j;
29 }
30 T_QUIET; T_ASSERT_EQ(write(fd, arr, sizeof(arr)), sizeof(arr), "write");
31 }
32
33 return fd;
34 }
35
36 #define K(n) ((n) << 10)
37
38 static struct mmap_spec {
39 int prot;
40 int flags;
41 uint32_t offs;
42 uint32_t size;
43 } specs[] = {
44 { PROT_READ, MAP_PRIVATE, K(0), N_SIZE - K(0) },
45 { PROT_READ, MAP_PRIVATE, K(1), N_SIZE - K(1) },
46 { PROT_READ, MAP_PRIVATE, K(4), N_SIZE - K(4) },
47 { PROT_READ, MAP_PRIVATE, K(8), N_SIZE - K(8) },
48 { PROT_READ, MAP_PRIVATE, K(16), N_SIZE - K(16) },
49 { PROT_READ, MAP_PRIVATE, K(32), N_SIZE - K(32) },
50 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(0), N_SIZE - K(0) },
51 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(1), N_SIZE - K(1) },
52 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(4), N_SIZE - K(4) },
53 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(8), N_SIZE - K(8) },
54 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16), N_SIZE - K(16) },
55 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(32), N_SIZE - K(32) },
56
57 { PROT_READ, MAP_PRIVATE, K(16) + K(0), K(16) },
58 { PROT_READ, MAP_PRIVATE, K(16) + K(1), K(16) },
59 { PROT_READ, MAP_PRIVATE, K(16) + K(4), K(16) },
60 { PROT_READ, MAP_PRIVATE, K(16) + K(8), K(16) },
61 { PROT_READ, MAP_PRIVATE, K(16) + K(16), K(16) },
62 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(0), K(16) },
63 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(1), K(16) },
64 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(4), K(16) },
65 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(8), K(16) },
66 { PROT_READ, MAP_PRIVATE | MAP_UNIX03, K(16) + K(16), K(16) },
67
68 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(0), N_SIZE - K(0) },
69 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(1), N_SIZE - K(1) },
70 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(4), N_SIZE - K(4) },
71 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(8), N_SIZE - K(8) },
72 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16), N_SIZE - K(16) },
73 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(32), N_SIZE - K(32) },
74 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(0), N_SIZE - K(0) },
75 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(1), N_SIZE - K(1) },
76 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(4), N_SIZE - K(4) },
77 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(8), N_SIZE - K(8) },
78 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16), N_SIZE - K(16) },
79 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(32), N_SIZE - K(32) },
80
81 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(0), K(16) },
82 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(1), K(16) },
83 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(4), K(16) },
84 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(8), K(16) },
85 { PROT_READ, MAP_PRIVATE | MAP_FIXED, K(16) + K(16), K(16) },
86 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(0), K(16) },
87 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(1), K(16) },
88 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(4), K(16) },
89 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(8), K(16) },
90 { PROT_READ, MAP_PRIVATE | MAP_FIXED | MAP_UNIX03, K(16) + K(16), K(16) },
91 { ~0 }
92 };
93
94 T_DECL(mmap_unaligned, "basic testing of mmap with various sizes and alignments")
95 {
96 vm_region_basic_info_data_64_t info;
97 mach_msg_type_number_t icount = VM_REGION_BASIC_INFO_COUNT_64;
98 mach_vm_address_t f_addr, r_addr;
99 mach_vm_size_t f_size, r_size;
100 uint32_t delta, size;
101 uint32_t *p, *want_p;
102 kern_return_t kr;
103 int fd;
104
105 fd = make_temp_fd();
106
107 for (struct mmap_spec *it = specs; it->prot != ~0; it++) {
108 T_LOG("mmap(NULL, prot=%#x, flags=%#x, fd=%d, offs=%d, size=%d)",
109 it->prot, it->flags, fd, it->offs, it->size);
110
111 if (it->flags & MAP_FIXED) {
112 f_size = PAGE_SIZE * 2 + it->size;
113 kr = mach_vm_allocate(mach_task_self(), &f_addr, f_size,
114 VM_FLAGS_ANYWHERE);
115 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "allocate VA");
116 want_p = (uint32_t *)(f_addr + PAGE_SIZE +
117 (it->offs & PAGE_MASK));
118 } else {
119 f_addr = 0;
120 f_size = 0;
121 want_p = NULL;
122 }
123
124 p = __mmap(want_p, it->size, it->prot, it->flags, fd, it->offs);
125
126 if ((it->flags & MAP_UNIX03) && (it->offs & PAGE_MASK)) {
127 errno_t rc = errno;
128 T_QUIET; T_EXPECT_EQ((void *)p, MAP_FAILED, "mmap failure");
129 T_QUIET; T_EXPECT_EQ(rc, EINVAL, "check errno");
130 continue;
131 } else if (want_p) {
132 T_QUIET; T_EXPECT_EQ((void *)p, want_p, "mmap success");
133 } else {
134 T_QUIET; T_EXPECT_NE((void *)p, MAP_FAILED, "mmap success");
135 }
136 T_QUIET; T_EXPECT_EQ((uint32_t)p & PAGE_MASK, it->offs & PAGE_MASK,
137 "check offset");
138
139 delta = it->offs & PAGE_MASK;
140 size = (delta + it->size + PAGE_MASK) & ~PAGE_MASK;
141 r_addr = (vm_offset_t)p;
142 kr = mach_vm_region(mach_task_self(), &r_addr, &r_size,
143 VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &icount,
144 &(mach_port_t){0});
145 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "region");
146 T_QUIET; T_EXPECT_EQ(r_addr, (mach_vm_address_t)p - delta,
147 "validate addr");
148 T_QUIET; T_EXPECT_EQ(r_size, (mach_vm_size_t)size,
149 "validate size");
150
151 for (uint32_t i = 0; i < it->size / 4; i += PAGE_SIZE / 4) {
152 T_QUIET; T_EXPECT_EQ(p[i], it->offs / 4 + i + 1u,
153 "check value");
154 }
155
156 if (f_addr) {
157 kr = mach_vm_deallocate(mach_task_self(), f_addr, f_size);
158 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "deallocate VA");
159 } else {
160 /* mmap doesn't allow misaligned things ... */
161 p -= delta / 4;
162 T_QUIET; T_EXPECT_POSIX_SUCCESS(munmap(p, size), 0,
163 "munmap(%p, %d)", p, size);
164 }
165 }
166 }
167