1 //===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Support/Memory.h"
10 #include "llvm/Support/Process.h"
11 #include "gtest/gtest.h"
12 #include <cassert>
13 #include <cstdlib>
14
15 #if defined(__NetBSD__)
16 // clang-format off
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/sysctl.h>
20 #include <err.h>
21 #include <unistd.h>
22 // clang-format on
23 #endif
24
25 using namespace llvm;
26 using namespace sys;
27
28 namespace {
29
IsMPROTECT()30 bool IsMPROTECT() {
31 #if defined(__NetBSD__)
32 int mib[3];
33 int paxflags;
34 size_t len = sizeof(paxflags);
35
36 mib[0] = CTL_PROC;
37 mib[1] = getpid();
38 mib[2] = PROC_PID_PAXFLAGS;
39
40 if (sysctl(mib, 3, &paxflags, &len, NULL, 0) != 0)
41 err(EXIT_FAILURE, "sysctl");
42
43 return !!(paxflags & CTL_PROC_PAXFLAGS_MPROTECT);
44 #elif defined(__APPLE__) && defined(__aarch64__)
45 return true;
46 #else
47 return false;
48 #endif
49 }
50
51 class MappedMemoryTest : public ::testing::TestWithParam<unsigned> {
52 public:
MappedMemoryTest()53 MappedMemoryTest() {
54 Flags = GetParam();
55 PageSize = sys::Process::getPageSizeEstimate();
56 }
57
58 protected:
59 // Adds RW flags to permit testing of the resulting memory
getTestableEquivalent(unsigned RequestedFlags)60 unsigned getTestableEquivalent(unsigned RequestedFlags) {
61 switch (RequestedFlags) {
62 case Memory::MF_READ:
63 case Memory::MF_WRITE:
64 case Memory::MF_READ|Memory::MF_WRITE:
65 return Memory::MF_READ|Memory::MF_WRITE;
66 case Memory::MF_READ|Memory::MF_EXEC:
67 case Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC:
68 case Memory::MF_EXEC:
69 return Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC;
70 }
71 // Default in case values are added to the enum, as required by some compilers
72 return Memory::MF_READ|Memory::MF_WRITE;
73 }
74
75 // Returns true if the memory blocks overlap
doesOverlap(MemoryBlock M1,MemoryBlock M2)76 bool doesOverlap(MemoryBlock M1, MemoryBlock M2) {
77 if (M1.base() == M2.base())
78 return true;
79
80 if (M1.base() > M2.base())
81 return (unsigned char *)M2.base() + M2.allocatedSize() > M1.base();
82
83 return (unsigned char *)M1.base() + M1.allocatedSize() > M2.base();
84 }
85
86 unsigned Flags;
87 size_t PageSize;
88 };
89
90 // MPROTECT prevents W+X mmaps
91 #define CHECK_UNSUPPORTED() \
92 do { \
93 if ((Flags & Memory::MF_WRITE) && (Flags & Memory::MF_EXEC) && \
94 IsMPROTECT()) \
95 return; \
96 } while (0)
97
TEST_P(MappedMemoryTest,AllocAndRelease)98 TEST_P(MappedMemoryTest, AllocAndRelease) {
99 CHECK_UNSUPPORTED();
100 std::error_code EC;
101 MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,EC);
102 EXPECT_EQ(std::error_code(), EC);
103
104 EXPECT_NE((void*)nullptr, M1.base());
105 EXPECT_LE(sizeof(int), M1.allocatedSize());
106
107 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
108 }
109
TEST_P(MappedMemoryTest,AllocAndReleaseHuge)110 TEST_P(MappedMemoryTest, AllocAndReleaseHuge) {
111 CHECK_UNSUPPORTED();
112 std::error_code EC;
113 MemoryBlock M1 = Memory::allocateMappedMemory(
114 sizeof(int), nullptr, Flags | Memory::MF_HUGE_HINT, EC);
115 EXPECT_EQ(std::error_code(), EC);
116
117 // Test large/huge memory pages. In the worst case, 4kb pages should be
118 // returned, if large pages aren't available.
119
120 EXPECT_NE((void *)nullptr, M1.base());
121 EXPECT_LE(sizeof(int), M1.allocatedSize());
122
123 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
124 }
125
TEST_P(MappedMemoryTest,MultipleAllocAndRelease)126 TEST_P(MappedMemoryTest, MultipleAllocAndRelease) {
127 CHECK_UNSUPPORTED();
128 std::error_code EC;
129 MemoryBlock M1 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
130 EXPECT_EQ(std::error_code(), EC);
131 MemoryBlock M2 = Memory::allocateMappedMemory(64, nullptr, Flags, EC);
132 EXPECT_EQ(std::error_code(), EC);
133 MemoryBlock M3 = Memory::allocateMappedMemory(32, nullptr, Flags, EC);
134 EXPECT_EQ(std::error_code(), EC);
135
136 EXPECT_NE((void*)nullptr, M1.base());
137 EXPECT_LE(16U, M1.allocatedSize());
138 EXPECT_NE((void*)nullptr, M2.base());
139 EXPECT_LE(64U, M2.allocatedSize());
140 EXPECT_NE((void*)nullptr, M3.base());
141 EXPECT_LE(32U, M3.allocatedSize());
142
143 EXPECT_FALSE(doesOverlap(M1, M2));
144 EXPECT_FALSE(doesOverlap(M2, M3));
145 EXPECT_FALSE(doesOverlap(M1, M3));
146
147 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
148 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
149 MemoryBlock M4 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
150 EXPECT_EQ(std::error_code(), EC);
151 EXPECT_NE((void*)nullptr, M4.base());
152 EXPECT_LE(16U, M4.allocatedSize());
153 EXPECT_FALSE(Memory::releaseMappedMemory(M4));
154 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
155 }
156
TEST_P(MappedMemoryTest,BasicWrite)157 TEST_P(MappedMemoryTest, BasicWrite) {
158 // This test applies only to readable and writeable combinations
159 if (Flags &&
160 !((Flags & Memory::MF_READ) && (Flags & Memory::MF_WRITE)))
161 return;
162 CHECK_UNSUPPORTED();
163
164 std::error_code EC;
165 MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,EC);
166 EXPECT_EQ(std::error_code(), EC);
167
168 EXPECT_NE((void*)nullptr, M1.base());
169 EXPECT_LE(sizeof(int), M1.allocatedSize());
170
171 int *a = (int*)M1.base();
172 *a = 1;
173 EXPECT_EQ(1, *a);
174
175 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
176 }
177
TEST_P(MappedMemoryTest,MultipleWrite)178 TEST_P(MappedMemoryTest, MultipleWrite) {
179 // This test applies only to readable and writeable combinations
180 if (Flags &&
181 !((Flags & Memory::MF_READ) && (Flags & Memory::MF_WRITE)))
182 return;
183 CHECK_UNSUPPORTED();
184
185 std::error_code EC;
186 MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,
187 EC);
188 EXPECT_EQ(std::error_code(), EC);
189 MemoryBlock M2 = Memory::allocateMappedMemory(8 * sizeof(int), nullptr, Flags,
190 EC);
191 EXPECT_EQ(std::error_code(), EC);
192 MemoryBlock M3 = Memory::allocateMappedMemory(4 * sizeof(int), nullptr, Flags,
193 EC);
194 EXPECT_EQ(std::error_code(), EC);
195
196 EXPECT_FALSE(doesOverlap(M1, M2));
197 EXPECT_FALSE(doesOverlap(M2, M3));
198 EXPECT_FALSE(doesOverlap(M1, M3));
199
200 EXPECT_NE((void*)nullptr, M1.base());
201 EXPECT_LE(1U * sizeof(int), M1.allocatedSize());
202 EXPECT_NE((void*)nullptr, M2.base());
203 EXPECT_LE(8U * sizeof(int), M2.allocatedSize());
204 EXPECT_NE((void*)nullptr, M3.base());
205 EXPECT_LE(4U * sizeof(int), M3.allocatedSize());
206
207 int *x = (int*)M1.base();
208 *x = 1;
209
210 int *y = (int*)M2.base();
211 for (int i = 0; i < 8; i++) {
212 y[i] = i;
213 }
214
215 int *z = (int*)M3.base();
216 *z = 42;
217
218 EXPECT_EQ(1, *x);
219 EXPECT_EQ(7, y[7]);
220 EXPECT_EQ(42, *z);
221
222 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
223 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
224
225 MemoryBlock M4 = Memory::allocateMappedMemory(64 * sizeof(int), nullptr,
226 Flags, EC);
227 EXPECT_EQ(std::error_code(), EC);
228 EXPECT_NE((void*)nullptr, M4.base());
229 EXPECT_LE(64U * sizeof(int), M4.allocatedSize());
230 x = (int*)M4.base();
231 *x = 4;
232 EXPECT_EQ(4, *x);
233 EXPECT_FALSE(Memory::releaseMappedMemory(M4));
234
235 // Verify that M2 remains unaffected by other activity
236 for (int i = 0; i < 8; i++) {
237 EXPECT_EQ(i, y[i]);
238 }
239 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
240 }
241
TEST_P(MappedMemoryTest,EnabledWrite)242 TEST_P(MappedMemoryTest, EnabledWrite) {
243 // MPROTECT prevents W+X, and since this test always adds W we need
244 // to block any variant with X.
245 if ((Flags & Memory::MF_EXEC) && IsMPROTECT())
246 return;
247
248 std::error_code EC;
249 MemoryBlock M1 = Memory::allocateMappedMemory(2 * sizeof(int), nullptr, Flags,
250 EC);
251 EXPECT_EQ(std::error_code(), EC);
252 MemoryBlock M2 = Memory::allocateMappedMemory(8 * sizeof(int), nullptr, Flags,
253 EC);
254 EXPECT_EQ(std::error_code(), EC);
255 MemoryBlock M3 = Memory::allocateMappedMemory(4 * sizeof(int), nullptr, Flags,
256 EC);
257 EXPECT_EQ(std::error_code(), EC);
258
259 EXPECT_NE((void*)nullptr, M1.base());
260 EXPECT_LE(2U * sizeof(int), M1.allocatedSize());
261 EXPECT_NE((void*)nullptr, M2.base());
262 EXPECT_LE(8U * sizeof(int), M2.allocatedSize());
263 EXPECT_NE((void*)nullptr, M3.base());
264 EXPECT_LE(4U * sizeof(int), M3.allocatedSize());
265
266 EXPECT_FALSE(Memory::protectMappedMemory(M1, getTestableEquivalent(Flags)));
267 EXPECT_FALSE(Memory::protectMappedMemory(M2, getTestableEquivalent(Flags)));
268 EXPECT_FALSE(Memory::protectMappedMemory(M3, getTestableEquivalent(Flags)));
269
270 EXPECT_FALSE(doesOverlap(M1, M2));
271 EXPECT_FALSE(doesOverlap(M2, M3));
272 EXPECT_FALSE(doesOverlap(M1, M3));
273
274 int *x = (int*)M1.base();
275 *x = 1;
276 int *y = (int*)M2.base();
277 for (unsigned int i = 0; i < 8; i++) {
278 y[i] = i;
279 }
280 int *z = (int*)M3.base();
281 *z = 42;
282
283 EXPECT_EQ(1, *x);
284 EXPECT_EQ(7, y[7]);
285 EXPECT_EQ(42, *z);
286
287 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
288 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
289 EXPECT_EQ(6, y[6]);
290
291 MemoryBlock M4 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
292 EXPECT_EQ(std::error_code(), EC);
293 EXPECT_NE((void*)nullptr, M4.base());
294 EXPECT_LE(16U, M4.allocatedSize());
295 EXPECT_EQ(std::error_code(),
296 Memory::protectMappedMemory(M4, getTestableEquivalent(Flags)));
297 x = (int*)M4.base();
298 *x = 4;
299 EXPECT_EQ(4, *x);
300 EXPECT_FALSE(Memory::releaseMappedMemory(M4));
301 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
302 }
303
TEST_P(MappedMemoryTest,SuccessiveNear)304 TEST_P(MappedMemoryTest, SuccessiveNear) {
305 CHECK_UNSUPPORTED();
306 std::error_code EC;
307 MemoryBlock M1 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
308 EXPECT_EQ(std::error_code(), EC);
309 MemoryBlock M2 = Memory::allocateMappedMemory(64, &M1, Flags, EC);
310 EXPECT_EQ(std::error_code(), EC);
311 MemoryBlock M3 = Memory::allocateMappedMemory(32, &M2, Flags, EC);
312 EXPECT_EQ(std::error_code(), EC);
313
314 EXPECT_NE((void*)nullptr, M1.base());
315 EXPECT_LE(16U, M1.allocatedSize());
316 EXPECT_NE((void*)nullptr, M2.base());
317 EXPECT_LE(64U, M2.allocatedSize());
318 EXPECT_NE((void*)nullptr, M3.base());
319 EXPECT_LE(32U, M3.allocatedSize());
320
321 EXPECT_FALSE(doesOverlap(M1, M2));
322 EXPECT_FALSE(doesOverlap(M2, M3));
323 EXPECT_FALSE(doesOverlap(M1, M3));
324
325 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
326 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
327 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
328 }
329
TEST_P(MappedMemoryTest,DuplicateNear)330 TEST_P(MappedMemoryTest, DuplicateNear) {
331 CHECK_UNSUPPORTED();
332 std::error_code EC;
333 MemoryBlock Near((void*)(3*PageSize), 16);
334 MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
335 EXPECT_EQ(std::error_code(), EC);
336 MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
337 EXPECT_EQ(std::error_code(), EC);
338 MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
339 EXPECT_EQ(std::error_code(), EC);
340
341 EXPECT_NE((void*)nullptr, M1.base());
342 EXPECT_LE(16U, M1.allocatedSize());
343 EXPECT_NE((void*)nullptr, M2.base());
344 EXPECT_LE(64U, M2.allocatedSize());
345 EXPECT_NE((void*)nullptr, M3.base());
346 EXPECT_LE(32U, M3.allocatedSize());
347
348 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
349 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
350 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
351 }
352
TEST_P(MappedMemoryTest,ZeroNear)353 TEST_P(MappedMemoryTest, ZeroNear) {
354 CHECK_UNSUPPORTED();
355 std::error_code EC;
356 MemoryBlock Near(nullptr, 0);
357 MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
358 EXPECT_EQ(std::error_code(), EC);
359 MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
360 EXPECT_EQ(std::error_code(), EC);
361 MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
362 EXPECT_EQ(std::error_code(), EC);
363
364 EXPECT_NE((void*)nullptr, M1.base());
365 EXPECT_LE(16U, M1.allocatedSize());
366 EXPECT_NE((void*)nullptr, M2.base());
367 EXPECT_LE(64U, M2.allocatedSize());
368 EXPECT_NE((void*)nullptr, M3.base());
369 EXPECT_LE(32U, M3.allocatedSize());
370
371 EXPECT_FALSE(doesOverlap(M1, M2));
372 EXPECT_FALSE(doesOverlap(M2, M3));
373 EXPECT_FALSE(doesOverlap(M1, M3));
374
375 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
376 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
377 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
378 }
379
TEST_P(MappedMemoryTest,ZeroSizeNear)380 TEST_P(MappedMemoryTest, ZeroSizeNear) {
381 CHECK_UNSUPPORTED();
382 std::error_code EC;
383 MemoryBlock Near((void*)(4*PageSize), 0);
384 MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
385 EXPECT_EQ(std::error_code(), EC);
386 MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
387 EXPECT_EQ(std::error_code(), EC);
388 MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
389 EXPECT_EQ(std::error_code(), EC);
390
391 EXPECT_NE((void*)nullptr, M1.base());
392 EXPECT_LE(16U, M1.allocatedSize());
393 EXPECT_NE((void*)nullptr, M2.base());
394 EXPECT_LE(64U, M2.allocatedSize());
395 EXPECT_NE((void*)nullptr, M3.base());
396 EXPECT_LE(32U, M3.allocatedSize());
397
398 EXPECT_FALSE(doesOverlap(M1, M2));
399 EXPECT_FALSE(doesOverlap(M2, M3));
400 EXPECT_FALSE(doesOverlap(M1, M3));
401
402 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
403 EXPECT_FALSE(Memory::releaseMappedMemory(M3));
404 EXPECT_FALSE(Memory::releaseMappedMemory(M2));
405 }
406
TEST_P(MappedMemoryTest,UnalignedNear)407 TEST_P(MappedMemoryTest, UnalignedNear) {
408 CHECK_UNSUPPORTED();
409 std::error_code EC;
410 MemoryBlock Near((void*)(2*PageSize+5), 0);
411 MemoryBlock M1 = Memory::allocateMappedMemory(15, &Near, Flags, EC);
412 EXPECT_EQ(std::error_code(), EC);
413
414 EXPECT_NE((void*)nullptr, M1.base());
415 EXPECT_LE(sizeof(int), M1.allocatedSize());
416
417 EXPECT_FALSE(Memory::releaseMappedMemory(M1));
418 }
419
420 // Note that Memory::MF_WRITE is not supported exclusively across
421 // operating systems and architectures and can imply MF_READ|MF_WRITE
422 unsigned MemoryFlags[] = {
423 Memory::MF_READ,
424 Memory::MF_WRITE,
425 Memory::MF_READ|Memory::MF_WRITE,
426 Memory::MF_EXEC,
427 Memory::MF_READ|Memory::MF_EXEC,
428 Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC
429 };
430
431 INSTANTIATE_TEST_SUITE_P(AllocationTests, MappedMemoryTest,
432 ::testing::ValuesIn(MemoryFlags));
433
434 } // anonymous namespace
435