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