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