1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "mem_map.h"
18 
19 #include <memory>
20 #include <random>
21 
22 #include "bit_utils.h"
23 #include "common_art_test.h"
24 #include "logging.h"
25 #include "memory_tool.h"
26 #include "mman.h"
27 #include "unix_file/fd_file.h"
28 
29 namespace art {
30 
31 class MemMapTest : public CommonArtTest {
32  public:
IsAddressMapped(void * addr)33   static bool IsAddressMapped(void* addr) {
34     bool res = msync(addr, 1, MS_SYNC) == 0;
35     if (!res && errno != ENOMEM) {
36       PLOG(FATAL) << "Unexpected error occurred on msync";
37     }
38     return res;
39   }
40 
RandomData(size_t size)41   static std::vector<uint8_t> RandomData(size_t size) {
42     std::random_device rd;
43     std::uniform_int_distribution<uint8_t> dist;
44     std::vector<uint8_t> res;
45     res.resize(size);
46     for (size_t i = 0; i < size; i++) {
47       res[i] = dist(rd);
48     }
49     return res;
50   }
51 
GetValidMapAddress(size_t size,bool low_4gb)52   static uint8_t* GetValidMapAddress(size_t size, bool low_4gb) {
53     // Find a valid map address and unmap it before returning.
54     std::string error_msg;
55     MemMap map = MemMap::MapAnonymous("temp",
56                                       size,
57                                       PROT_READ,
58                                       low_4gb,
59                                       &error_msg);
60     CHECK(map.IsValid());
61     return map.Begin();
62   }
63 
RemapAtEndTest(bool low_4gb)64   static void RemapAtEndTest(bool low_4gb) {
65     std::string error_msg;
66     // Cast the page size to size_t.
67     const size_t page_size = static_cast<size_t>(kPageSize);
68     // Map a two-page memory region.
69     MemMap m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0",
70                                      2 * page_size,
71                                      PROT_READ | PROT_WRITE,
72                                      low_4gb,
73                                      &error_msg);
74     // Check its state and write to it.
75     ASSERT_TRUE(m0.IsValid());
76     uint8_t* base0 = m0.Begin();
77     ASSERT_TRUE(base0 != nullptr) << error_msg;
78     size_t size0 = m0.Size();
79     EXPECT_EQ(m0.Size(), 2 * page_size);
80     EXPECT_EQ(m0.BaseBegin(), base0);
81     EXPECT_EQ(m0.BaseSize(), size0);
82     memset(base0, 42, 2 * page_size);
83     // Remap the latter half into a second MemMap.
84     MemMap m1 = m0.RemapAtEnd(base0 + page_size,
85                               "MemMapTest_RemapAtEndTest_map1",
86                               PROT_READ | PROT_WRITE,
87                               &error_msg);
88     // Check the states of the two maps.
89     EXPECT_EQ(m0.Begin(), base0) << error_msg;
90     EXPECT_EQ(m0.Size(), page_size);
91     EXPECT_EQ(m0.BaseBegin(), base0);
92     EXPECT_EQ(m0.BaseSize(), page_size);
93     uint8_t* base1 = m1.Begin();
94     size_t size1 = m1.Size();
95     EXPECT_EQ(base1, base0 + page_size);
96     EXPECT_EQ(size1, page_size);
97     EXPECT_EQ(m1.BaseBegin(), base1);
98     EXPECT_EQ(m1.BaseSize(), size1);
99     // Write to the second region.
100     memset(base1, 43, page_size);
101     // Check the contents of the two regions.
102     for (size_t i = 0; i < page_size; ++i) {
103       EXPECT_EQ(base0[i], 42);
104     }
105     for (size_t i = 0; i < page_size; ++i) {
106       EXPECT_EQ(base1[i], 43);
107     }
108     // Unmap the first region.
109     m0.Reset();
110     // Make sure the second region is still accessible after the first
111     // region is unmapped.
112     for (size_t i = 0; i < page_size; ++i) {
113       EXPECT_EQ(base1[i], 43);
114     }
115     MemMap m2 = m1.RemapAtEnd(m1.Begin(),
116                               "MemMapTest_RemapAtEndTest_map1",
117                               PROT_READ | PROT_WRITE,
118                               &error_msg);
119     ASSERT_TRUE(m2.IsValid()) << error_msg;
120     ASSERT_FALSE(m1.IsValid());
121   }
122 
CommonInit()123   void CommonInit() {
124     MemMap::Init();
125   }
126 
127 #if defined(__LP64__) && !defined(__x86_64__)
GetLinearScanPos()128   static uintptr_t GetLinearScanPos() {
129     return MemMap::next_mem_pos_;
130   }
131 #endif
132 };
133 
134 #if defined(__LP64__) && !defined(__x86_64__)
135 
136 #ifdef __BIONIC__
137 extern uintptr_t CreateStartPos(uint64_t input);
138 #endif
139 
TEST_F(MemMapTest,Start)140 TEST_F(MemMapTest, Start) {
141   CommonInit();
142   uintptr_t start = GetLinearScanPos();
143   EXPECT_LE(64 * KB, start);
144   EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS));
145 #ifdef __BIONIC__
146   // Test a couple of values. Make sure they are different.
147   uintptr_t last = 0;
148   for (size_t i = 0; i < 100; ++i) {
149     uintptr_t random_start = CreateStartPos(i * kPageSize);
150     EXPECT_NE(last, random_start);
151     last = random_start;
152   }
153 
154   // Even on max, should be below ART_BASE_ADDRESS.
155   EXPECT_LT(CreateStartPos(~0), static_cast<uintptr_t>(ART_BASE_ADDRESS));
156 #endif
157   // End of test.
158 }
159 #endif
160 
161 // We need mremap to be able to test ReplaceMapping at all
162 #if HAVE_MREMAP_SYSCALL
TEST_F(MemMapTest,ReplaceMapping_SameSize)163 TEST_F(MemMapTest, ReplaceMapping_SameSize) {
164   std::string error_msg;
165   MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
166                                      kPageSize,
167                                      PROT_READ,
168                                      /*low_4gb=*/ false,
169                                      &error_msg);
170   ASSERT_TRUE(dest.IsValid());
171   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
172                                        kPageSize,
173                                        PROT_WRITE | PROT_READ,
174                                        /*low_4gb=*/ false,
175                                        &error_msg);
176   ASSERT_TRUE(source.IsValid());
177   void* source_addr = source.Begin();
178   void* dest_addr = dest.Begin();
179   ASSERT_TRUE(IsAddressMapped(source_addr));
180   ASSERT_TRUE(IsAddressMapped(dest_addr));
181 
182   std::vector<uint8_t> data = RandomData(kPageSize);
183   memcpy(source.Begin(), data.data(), data.size());
184 
185   ASSERT_TRUE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
186 
187   ASSERT_FALSE(IsAddressMapped(source_addr));
188   ASSERT_TRUE(IsAddressMapped(dest_addr));
189   ASSERT_FALSE(source.IsValid());
190 
191   ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
192 
193   ASSERT_EQ(memcmp(dest.Begin(), data.data(), dest.Size()), 0);
194 }
195 
TEST_F(MemMapTest,ReplaceMapping_MakeLarger)196 TEST_F(MemMapTest, ReplaceMapping_MakeLarger) {
197   std::string error_msg;
198   MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
199                                      5 * kPageSize,  // Need to make it larger
200                                                      // initially so we know
201                                                      // there won't be mappings
202                                                      // in the way when we move
203                                                      // source.
204                                      PROT_READ,
205                                      /*low_4gb=*/ false,
206                                      &error_msg);
207   ASSERT_TRUE(dest.IsValid());
208   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
209                                        3 * kPageSize,
210                                        PROT_WRITE | PROT_READ,
211                                        /*low_4gb=*/ false,
212                                        &error_msg);
213   ASSERT_TRUE(source.IsValid());
214   uint8_t* source_addr = source.Begin();
215   uint8_t* dest_addr = dest.Begin();
216   ASSERT_TRUE(IsAddressMapped(source_addr));
217 
218   // Fill the source with random data.
219   std::vector<uint8_t> data = RandomData(3 * kPageSize);
220   memcpy(source.Begin(), data.data(), data.size());
221 
222   // Make the dest smaller so that we know we'll have space.
223   dest.SetSize(kPageSize);
224 
225   ASSERT_TRUE(IsAddressMapped(dest_addr));
226   ASSERT_FALSE(IsAddressMapped(dest_addr + 2 * kPageSize));
227   ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
228 
229   ASSERT_TRUE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
230 
231   ASSERT_FALSE(IsAddressMapped(source_addr));
232   ASSERT_EQ(dest.Size(), static_cast<size_t>(3 * kPageSize));
233   ASSERT_TRUE(IsAddressMapped(dest_addr));
234   ASSERT_TRUE(IsAddressMapped(dest_addr + 2 * kPageSize));
235   ASSERT_FALSE(source.IsValid());
236 
237   ASSERT_EQ(memcmp(dest.Begin(), data.data(), dest.Size()), 0);
238 }
239 
TEST_F(MemMapTest,ReplaceMapping_MakeSmaller)240 TEST_F(MemMapTest, ReplaceMapping_MakeSmaller) {
241   std::string error_msg;
242   MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
243                                      3 * kPageSize,
244                                      PROT_READ,
245                                      /*low_4gb=*/ false,
246                                      &error_msg);
247   ASSERT_TRUE(dest.IsValid());
248   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
249                                        kPageSize,
250                                        PROT_WRITE | PROT_READ,
251                                        /*low_4gb=*/ false,
252                                        &error_msg);
253   ASSERT_TRUE(source.IsValid());
254   uint8_t* source_addr = source.Begin();
255   uint8_t* dest_addr = dest.Begin();
256   ASSERT_TRUE(IsAddressMapped(source_addr));
257   ASSERT_TRUE(IsAddressMapped(dest_addr));
258   ASSERT_TRUE(IsAddressMapped(dest_addr + 2 * kPageSize));
259   ASSERT_EQ(dest.Size(), static_cast<size_t>(3 * kPageSize));
260 
261   std::vector<uint8_t> data = RandomData(kPageSize);
262   memcpy(source.Begin(), data.data(), kPageSize);
263 
264   ASSERT_TRUE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
265 
266   ASSERT_FALSE(IsAddressMapped(source_addr));
267   ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
268   ASSERT_TRUE(IsAddressMapped(dest_addr));
269   ASSERT_FALSE(IsAddressMapped(dest_addr + 2 * kPageSize));
270   ASSERT_FALSE(source.IsValid());
271 
272   ASSERT_EQ(memcmp(dest.Begin(), data.data(), dest.Size()), 0);
273 }
274 
TEST_F(MemMapTest,ReplaceMapping_FailureOverlap)275 TEST_F(MemMapTest, ReplaceMapping_FailureOverlap) {
276   std::string error_msg;
277   MemMap dest =
278       MemMap::MapAnonymous(
279           "MapAnonymousEmpty-atomic-replace-dest",
280           3 * kPageSize,  // Need to make it larger initially so we know there won't be mappings in
281                           // the way when we move source.
282           PROT_READ | PROT_WRITE,
283           /*low_4gb=*/ false,
284           &error_msg);
285   ASSERT_TRUE(dest.IsValid());
286   // Resize down to 1 page so we can remap the rest.
287   dest.SetSize(kPageSize);
288   // Create source from the last 2 pages
289   MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
290                                        dest.Begin() + kPageSize,
291                                        2 * kPageSize,
292                                        PROT_WRITE | PROT_READ,
293                                        /*low_4gb=*/ false,
294                                        /*reuse=*/ false,
295                                        /*reservation=*/ nullptr,
296                                        &error_msg);
297   ASSERT_TRUE(source.IsValid());
298   ASSERT_EQ(dest.Begin() + kPageSize, source.Begin());
299   uint8_t* source_addr = source.Begin();
300   uint8_t* dest_addr = dest.Begin();
301   ASSERT_TRUE(IsAddressMapped(source_addr));
302 
303   // Fill the source and dest with random data.
304   std::vector<uint8_t> data = RandomData(2 * kPageSize);
305   memcpy(source.Begin(), data.data(), data.size());
306   std::vector<uint8_t> dest_data = RandomData(kPageSize);
307   memcpy(dest.Begin(), dest_data.data(), dest_data.size());
308 
309   ASSERT_TRUE(IsAddressMapped(dest_addr));
310   ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
311 
312   ASSERT_FALSE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
313 
314   ASSERT_TRUE(IsAddressMapped(source_addr));
315   ASSERT_TRUE(IsAddressMapped(dest_addr));
316   ASSERT_EQ(source.Size(), data.size());
317   ASSERT_EQ(dest.Size(), dest_data.size());
318 
319   ASSERT_EQ(memcmp(source.Begin(), data.data(), data.size()), 0);
320   ASSERT_EQ(memcmp(dest.Begin(), dest_data.data(), dest_data.size()), 0);
321 }
322 #endif  // HAVE_MREMAP_SYSCALL
323 
TEST_F(MemMapTest,MapAnonymousEmpty)324 TEST_F(MemMapTest, MapAnonymousEmpty) {
325   CommonInit();
326   std::string error_msg;
327   MemMap map = MemMap::MapAnonymous("MapAnonymousEmpty",
328                                     /*byte_count=*/ 0,
329                                     PROT_READ,
330                                     /*low_4gb=*/ false,
331                                     &error_msg);
332   ASSERT_FALSE(map.IsValid()) << error_msg;
333   ASSERT_FALSE(error_msg.empty());
334 
335   error_msg.clear();
336   map = MemMap::MapAnonymous("MapAnonymousNonEmpty",
337                              kPageSize,
338                              PROT_READ | PROT_WRITE,
339                              /*low_4gb=*/ false,
340                              &error_msg);
341   ASSERT_TRUE(map.IsValid()) << error_msg;
342   ASSERT_TRUE(error_msg.empty());
343 }
344 
TEST_F(MemMapTest,MapAnonymousFailNullError)345 TEST_F(MemMapTest, MapAnonymousFailNullError) {
346   CommonInit();
347   // Test that we don't crash with a null error_str when mapping at an invalid location.
348   MemMap map = MemMap::MapAnonymous("MapAnonymousInvalid",
349                                     reinterpret_cast<uint8_t*>(kPageSize),
350                                     0x20000,
351                                     PROT_READ | PROT_WRITE,
352                                     /*low_4gb=*/ false,
353                                     /*reuse=*/ false,
354                                     /*reservation=*/ nullptr,
355                                     nullptr);
356   ASSERT_FALSE(map.IsValid());
357 }
358 
359 #ifdef __LP64__
TEST_F(MemMapTest,MapAnonymousEmpty32bit)360 TEST_F(MemMapTest, MapAnonymousEmpty32bit) {
361   CommonInit();
362   std::string error_msg;
363   MemMap map = MemMap::MapAnonymous("MapAnonymousEmpty",
364                                     /*byte_count=*/ 0,
365                                     PROT_READ,
366                                     /*low_4gb=*/ true,
367                                     &error_msg);
368   ASSERT_FALSE(map.IsValid()) << error_msg;
369   ASSERT_FALSE(error_msg.empty());
370 
371   error_msg.clear();
372   map = MemMap::MapAnonymous("MapAnonymousNonEmpty",
373                              kPageSize,
374                              PROT_READ | PROT_WRITE,
375                              /*low_4gb=*/ true,
376                              &error_msg);
377   ASSERT_TRUE(map.IsValid()) << error_msg;
378   ASSERT_TRUE(error_msg.empty());
379   ASSERT_LT(reinterpret_cast<uintptr_t>(map.BaseBegin()), 1ULL << 32);
380 }
TEST_F(MemMapTest,MapFile32Bit)381 TEST_F(MemMapTest, MapFile32Bit) {
382   CommonInit();
383   std::string error_msg;
384   ScratchFile scratch_file;
385   constexpr size_t kMapSize = kPageSize;
386   std::unique_ptr<uint8_t[]> data(new uint8_t[kMapSize]());
387   ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
388   MemMap map = MemMap::MapFile(/*byte_count=*/kMapSize,
389                                PROT_READ,
390                                MAP_PRIVATE,
391                                scratch_file.GetFd(),
392                                /*start=*/0,
393                                /*low_4gb=*/true,
394                                scratch_file.GetFilename().c_str(),
395                                &error_msg);
396   ASSERT_TRUE(map.IsValid()) << error_msg;
397   ASSERT_TRUE(error_msg.empty());
398   ASSERT_EQ(map.Size(), kMapSize);
399   ASSERT_LT(reinterpret_cast<uintptr_t>(map.BaseBegin()), 1ULL << 32);
400 }
401 #endif
402 
TEST_F(MemMapTest,MapAnonymousExactAddr)403 TEST_F(MemMapTest, MapAnonymousExactAddr) {
404   // TODO: The semantics of the MemMap::MapAnonymous() with a given address but without
405   // `reuse == true` or `reservation != nullptr` is weird. We should either drop support
406   // for it, or take it only as a hint and allow the result to be mapped elsewhere.
407   // Currently we're seeing failures with ASAN. b/118408378
408   TEST_DISABLED_FOR_MEMORY_TOOL();
409 
410   CommonInit();
411   std::string error_msg;
412   // Find a valid address.
413   uint8_t* valid_address = GetValidMapAddress(kPageSize, /*low_4gb=*/false);
414   // Map at an address that should work, which should succeed.
415   MemMap map0 = MemMap::MapAnonymous("MapAnonymous0",
416                                      valid_address,
417                                      kPageSize,
418                                      PROT_READ | PROT_WRITE,
419                                      /*low_4gb=*/ false,
420                                      /*reuse=*/ false,
421                                      /*reservation=*/ nullptr,
422                                      &error_msg);
423   ASSERT_TRUE(map0.IsValid()) << error_msg;
424   ASSERT_TRUE(error_msg.empty());
425   ASSERT_TRUE(map0.BaseBegin() == valid_address);
426   // Map at an unspecified address, which should succeed.
427   MemMap map1 = MemMap::MapAnonymous("MapAnonymous1",
428                                      kPageSize,
429                                      PROT_READ | PROT_WRITE,
430                                      /*low_4gb=*/ false,
431                                      &error_msg);
432   ASSERT_TRUE(map1.IsValid()) << error_msg;
433   ASSERT_TRUE(error_msg.empty());
434   ASSERT_TRUE(map1.BaseBegin() != nullptr);
435   // Attempt to map at the same address, which should fail.
436   MemMap map2 = MemMap::MapAnonymous("MapAnonymous2",
437                                      reinterpret_cast<uint8_t*>(map1.BaseBegin()),
438                                      kPageSize,
439                                      PROT_READ | PROT_WRITE,
440                                      /*low_4gb=*/ false,
441                                      /*reuse=*/ false,
442                                      /*reservation=*/ nullptr,
443                                      &error_msg);
444   ASSERT_FALSE(map2.IsValid()) << error_msg;
445   ASSERT_TRUE(!error_msg.empty());
446 }
447 
TEST_F(MemMapTest,RemapAtEnd)448 TEST_F(MemMapTest, RemapAtEnd) {
449   RemapAtEndTest(false);
450 }
451 
452 #ifdef __LP64__
TEST_F(MemMapTest,RemapAtEnd32bit)453 TEST_F(MemMapTest, RemapAtEnd32bit) {
454   RemapAtEndTest(true);
455 }
456 #endif
457 
TEST_F(MemMapTest,RemapFileViewAtEnd)458 TEST_F(MemMapTest, RemapFileViewAtEnd) {
459   CommonInit();
460   std::string error_msg;
461   ScratchFile scratch_file;
462 
463   // Create a scratch file 3 pages large.
464   constexpr size_t kMapSize = 3 * kPageSize;
465   std::unique_ptr<uint8_t[]> data(new uint8_t[kMapSize]());
466   memset(data.get(), 1, kPageSize);
467   memset(&data[0], 0x55, kPageSize);
468   memset(&data[kPageSize], 0x5a, kPageSize);
469   memset(&data[2 * kPageSize], 0xaa, kPageSize);
470   ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
471 
472   MemMap map = MemMap::MapFile(/*byte_count=*/kMapSize,
473                                PROT_READ,
474                                MAP_PRIVATE,
475                                scratch_file.GetFd(),
476                                /*start=*/0,
477                                /*low_4gb=*/true,
478                                scratch_file.GetFilename().c_str(),
479                                &error_msg);
480   ASSERT_TRUE(map.IsValid()) << error_msg;
481   ASSERT_TRUE(error_msg.empty());
482   ASSERT_EQ(map.Size(), kMapSize);
483   ASSERT_LT(reinterpret_cast<uintptr_t>(map.BaseBegin()), 1ULL << 32);
484   ASSERT_EQ(data[0], *map.Begin());
485   ASSERT_EQ(data[kPageSize], *(map.Begin() + kPageSize));
486   ASSERT_EQ(data[2 * kPageSize], *(map.Begin() + 2 * kPageSize));
487 
488   for (size_t offset = 2 * kPageSize; offset > 0; offset -= kPageSize) {
489     MemMap tail = map.RemapAtEnd(map.Begin() + offset,
490                                  "bad_offset_map",
491                                  PROT_READ,
492                                  MAP_PRIVATE | MAP_FIXED,
493                                  scratch_file.GetFd(),
494                                  offset,
495                                  &error_msg);
496     ASSERT_TRUE(tail.IsValid()) << error_msg;
497     ASSERT_TRUE(error_msg.empty());
498     ASSERT_EQ(offset, map.Size());
499     ASSERT_EQ(static_cast<size_t>(kPageSize), tail.Size());
500     ASSERT_EQ(tail.Begin(), map.Begin() + map.Size());
501     ASSERT_EQ(data[offset], *tail.Begin());
502   }
503 }
504 
TEST_F(MemMapTest,MapAnonymousExactAddr32bitHighAddr)505 TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
506   // This test does not work under AddressSanitizer.
507   // Historical note: This test did not work under Valgrind either.
508   TEST_DISABLED_FOR_MEMORY_TOOL();
509 
510   CommonInit();
511   constexpr size_t size = 0x100000;
512   // Try all addresses starting from 2GB to 4GB.
513   size_t start_addr = 2 * GB;
514   std::string error_msg;
515   MemMap map;
516   for (; start_addr <= std::numeric_limits<uint32_t>::max() - size; start_addr += size) {
517     map = MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
518                                reinterpret_cast<uint8_t*>(start_addr),
519                                size,
520                                PROT_READ | PROT_WRITE,
521                                /*low_4gb=*/ true,
522                                /*reuse=*/ false,
523                                /*reservation=*/ nullptr,
524                                &error_msg);
525     if (map.IsValid()) {
526       break;
527     }
528   }
529   ASSERT_TRUE(map.IsValid()) << error_msg;
530   ASSERT_GE(reinterpret_cast<uintptr_t>(map.End()), 2u * GB);
531   ASSERT_TRUE(error_msg.empty());
532   ASSERT_EQ(map.BaseBegin(), reinterpret_cast<void*>(start_addr));
533 }
534 
TEST_F(MemMapTest,MapAnonymousOverflow)535 TEST_F(MemMapTest, MapAnonymousOverflow) {
536   CommonInit();
537   std::string error_msg;
538   uintptr_t ptr = 0;
539   ptr -= kPageSize;  // Now it's close to the top.
540   MemMap map = MemMap::MapAnonymous("MapAnonymousOverflow",
541                                     reinterpret_cast<uint8_t*>(ptr),
542                                     2 * kPageSize,  // brings it over the top.
543                                     PROT_READ | PROT_WRITE,
544                                     /*low_4gb=*/ false,
545                                     /*reuse=*/ false,
546                                     /*reservation=*/ nullptr,
547                                     &error_msg);
548   ASSERT_FALSE(map.IsValid());
549   ASSERT_FALSE(error_msg.empty());
550 }
551 
552 #ifdef __LP64__
TEST_F(MemMapTest,MapAnonymousLow4GBExpectedTooHigh)553 TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
554   CommonInit();
555   std::string error_msg;
556   MemMap map =
557       MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
558                            reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
559                            kPageSize,
560                            PROT_READ | PROT_WRITE,
561                            /*low_4gb=*/ true,
562                            /*reuse=*/ false,
563                            /*reservation=*/ nullptr,
564                            &error_msg);
565   ASSERT_FALSE(map.IsValid());
566   ASSERT_FALSE(error_msg.empty());
567 }
568 
TEST_F(MemMapTest,MapAnonymousLow4GBRangeTooHigh)569 TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
570   CommonInit();
571   std::string error_msg;
572   MemMap map = MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
573                                     /*addr=*/ reinterpret_cast<uint8_t*>(0xF0000000),
574                                     /*byte_count=*/ 0x20000000,
575                                     PROT_READ | PROT_WRITE,
576                                     /*low_4gb=*/ true,
577                                     /*reuse=*/ false,
578                                     /*reservation=*/ nullptr,
579                                     &error_msg);
580   ASSERT_FALSE(map.IsValid());
581   ASSERT_FALSE(error_msg.empty());
582 }
583 #endif
584 
TEST_F(MemMapTest,MapAnonymousReuse)585 TEST_F(MemMapTest, MapAnonymousReuse) {
586   CommonInit();
587   std::string error_msg;
588   MemMap map = MemMap::MapAnonymous("MapAnonymousReserve",
589                                     /*byte_count=*/ 0x20000,
590                                     PROT_READ | PROT_WRITE,
591                                     /*low_4gb=*/ false,
592                                     &error_msg);
593   ASSERT_TRUE(map.IsValid());
594   ASSERT_TRUE(error_msg.empty());
595   MemMap map2 = MemMap::MapAnonymous("MapAnonymousReused",
596                                      /*addr=*/ reinterpret_cast<uint8_t*>(map.BaseBegin()),
597                                      /*byte_count=*/ 0x10000,
598                                      PROT_READ | PROT_WRITE,
599                                      /*low_4gb=*/ false,
600                                      /*reuse=*/ true,
601                                      /*reservation=*/ nullptr,
602                                      &error_msg);
603   ASSERT_TRUE(map2.IsValid());
604   ASSERT_TRUE(error_msg.empty());
605 }
606 
TEST_F(MemMapTest,CheckNoGaps)607 TEST_F(MemMapTest, CheckNoGaps) {
608   CommonInit();
609   std::string error_msg;
610   constexpr size_t kNumPages = 3;
611   // Map a 3-page mem map.
612   MemMap reservation = MemMap::MapAnonymous("MapAnonymous0",
613                                             kPageSize * kNumPages,
614                                             PROT_READ | PROT_WRITE,
615                                             /*low_4gb=*/ false,
616                                             &error_msg);
617   ASSERT_TRUE(reservation.IsValid()) << error_msg;
618   ASSERT_TRUE(error_msg.empty());
619   // Record the base address.
620   uint8_t* map_base = reinterpret_cast<uint8_t*>(reservation.BaseBegin());
621 
622   // Map at the same address, taking from the `map` reservation.
623   MemMap map0 = MemMap::MapAnonymous("MapAnonymous0",
624                                      kPageSize,
625                                      PROT_READ | PROT_WRITE,
626                                      /*low_4gb=*/ false,
627                                      &reservation,
628                                      &error_msg);
629   ASSERT_TRUE(map0.IsValid()) << error_msg;
630   ASSERT_TRUE(error_msg.empty());
631   ASSERT_EQ(map_base, map0.Begin());
632   MemMap map1 = MemMap::MapAnonymous("MapAnonymous1",
633                                      kPageSize,
634                                      PROT_READ | PROT_WRITE,
635                                      /*low_4gb=*/ false,
636                                      &reservation,
637                                      &error_msg);
638   ASSERT_TRUE(map1.IsValid()) << error_msg;
639   ASSERT_TRUE(error_msg.empty());
640   ASSERT_EQ(map_base + kPageSize, map1.Begin());
641   MemMap map2 = MemMap::MapAnonymous("MapAnonymous2",
642                                      kPageSize,
643                                      PROT_READ | PROT_WRITE,
644                                      /*low_4gb=*/ false,
645                                      &reservation,
646                                      &error_msg);
647   ASSERT_TRUE(map2.IsValid()) << error_msg;
648   ASSERT_TRUE(error_msg.empty());
649   ASSERT_EQ(map_base + 2 * kPageSize, map2.Begin());
650   ASSERT_FALSE(reservation.IsValid());  // The entire reservation was used.
651 
652   // One-map cases.
653   ASSERT_TRUE(MemMap::CheckNoGaps(map0, map0));
654   ASSERT_TRUE(MemMap::CheckNoGaps(map1, map1));
655   ASSERT_TRUE(MemMap::CheckNoGaps(map2, map2));
656 
657   // Two or three-map cases.
658   ASSERT_TRUE(MemMap::CheckNoGaps(map0, map1));
659   ASSERT_TRUE(MemMap::CheckNoGaps(map1, map2));
660   ASSERT_TRUE(MemMap::CheckNoGaps(map0, map2));
661 
662   // Unmap the middle one.
663   map1.Reset();
664 
665   // Should return false now that there's a gap in the middle.
666   ASSERT_FALSE(MemMap::CheckNoGaps(map0, map2));
667 }
668 
TEST_F(MemMapTest,AlignBy)669 TEST_F(MemMapTest, AlignBy) {
670   CommonInit();
671   std::string error_msg;
672   // Cast the page size to size_t.
673   const size_t page_size = static_cast<size_t>(kPageSize);
674   // Map a region.
675   MemMap m0 = MemMap::MapAnonymous("MemMapTest_AlignByTest_map0",
676                                    14 * page_size,
677                                    PROT_READ | PROT_WRITE,
678                                    /*low_4gb=*/ false,
679                                    &error_msg);
680   ASSERT_TRUE(m0.IsValid());
681   uint8_t* base0 = m0.Begin();
682   ASSERT_TRUE(base0 != nullptr) << error_msg;
683   ASSERT_EQ(m0.Size(), 14 * page_size);
684   ASSERT_EQ(m0.BaseBegin(), base0);
685   ASSERT_EQ(m0.BaseSize(), m0.Size());
686 
687   // Break it into several regions by using RemapAtEnd.
688   MemMap m1 = m0.RemapAtEnd(base0 + 3 * page_size,
689                             "MemMapTest_AlignByTest_map1",
690                             PROT_READ | PROT_WRITE,
691                             &error_msg);
692   uint8_t* base1 = m1.Begin();
693   ASSERT_TRUE(base1 != nullptr) << error_msg;
694   ASSERT_EQ(base1, base0 + 3 * page_size);
695   ASSERT_EQ(m0.Size(), 3 * page_size);
696 
697   MemMap m2 = m1.RemapAtEnd(base1 + 4 * page_size,
698                             "MemMapTest_AlignByTest_map2",
699                             PROT_READ | PROT_WRITE,
700                             &error_msg);
701   uint8_t* base2 = m2.Begin();
702   ASSERT_TRUE(base2 != nullptr) << error_msg;
703   ASSERT_EQ(base2, base1 + 4 * page_size);
704   ASSERT_EQ(m1.Size(), 4 * page_size);
705 
706   MemMap m3 = m2.RemapAtEnd(base2 + 3 * page_size,
707                             "MemMapTest_AlignByTest_map1",
708                             PROT_READ | PROT_WRITE,
709                             &error_msg);
710   uint8_t* base3 = m3.Begin();
711   ASSERT_TRUE(base3 != nullptr) << error_msg;
712   ASSERT_EQ(base3, base2 + 3 * page_size);
713   ASSERT_EQ(m2.Size(), 3 * page_size);
714   ASSERT_EQ(m3.Size(), 4 * page_size);
715 
716   uint8_t* end0 = base0 + m0.Size();
717   uint8_t* end1 = base1 + m1.Size();
718   uint8_t* end2 = base2 + m2.Size();
719   uint8_t* end3 = base3 + m3.Size();
720 
721   ASSERT_EQ(static_cast<size_t>(end3 - base0), 14 * page_size);
722 
723   if (IsAlignedParam(base0, 2 * page_size)) {
724     ASSERT_FALSE(IsAlignedParam(base1, 2 * page_size));
725     ASSERT_FALSE(IsAlignedParam(base2, 2 * page_size));
726     ASSERT_TRUE(IsAlignedParam(base3, 2 * page_size));
727     ASSERT_TRUE(IsAlignedParam(end3, 2 * page_size));
728   } else {
729     ASSERT_TRUE(IsAlignedParam(base1, 2 * page_size));
730     ASSERT_TRUE(IsAlignedParam(base2, 2 * page_size));
731     ASSERT_FALSE(IsAlignedParam(base3, 2 * page_size));
732     ASSERT_FALSE(IsAlignedParam(end3, 2 * page_size));
733   }
734 
735   // Align by 2 * page_size;
736   m0.AlignBy(2 * page_size);
737   m1.AlignBy(2 * page_size);
738   m2.AlignBy(2 * page_size);
739   m3.AlignBy(2 * page_size);
740 
741   EXPECT_TRUE(IsAlignedParam(m0.Begin(), 2 * page_size));
742   EXPECT_TRUE(IsAlignedParam(m1.Begin(), 2 * page_size));
743   EXPECT_TRUE(IsAlignedParam(m2.Begin(), 2 * page_size));
744   EXPECT_TRUE(IsAlignedParam(m3.Begin(), 2 * page_size));
745 
746   EXPECT_TRUE(IsAlignedParam(m0.Begin() + m0.Size(), 2 * page_size));
747   EXPECT_TRUE(IsAlignedParam(m1.Begin() + m1.Size(), 2 * page_size));
748   EXPECT_TRUE(IsAlignedParam(m2.Begin() + m2.Size(), 2 * page_size));
749   EXPECT_TRUE(IsAlignedParam(m3.Begin() + m3.Size(), 2 * page_size));
750 
751   if (IsAlignedParam(base0, 2 * page_size)) {
752     EXPECT_EQ(m0.Begin(), base0);
753     EXPECT_EQ(m0.Begin() + m0.Size(), end0 - page_size);
754     EXPECT_EQ(m1.Begin(), base1 + page_size);
755     EXPECT_EQ(m1.Begin() + m1.Size(), end1 - page_size);
756     EXPECT_EQ(m2.Begin(), base2 + page_size);
757     EXPECT_EQ(m2.Begin() + m2.Size(), end2);
758     EXPECT_EQ(m3.Begin(), base3);
759     EXPECT_EQ(m3.Begin() + m3.Size(), end3);
760   } else {
761     EXPECT_EQ(m0.Begin(), base0 + page_size);
762     EXPECT_EQ(m0.Begin() + m0.Size(), end0);
763     EXPECT_EQ(m1.Begin(), base1);
764     EXPECT_EQ(m1.Begin() + m1.Size(), end1);
765     EXPECT_EQ(m2.Begin(), base2);
766     EXPECT_EQ(m2.Begin() + m2.Size(), end2 - page_size);
767     EXPECT_EQ(m3.Begin(), base3 + page_size);
768     EXPECT_EQ(m3.Begin() + m3.Size(), end3 - page_size);
769   }
770 }
771 
TEST_F(MemMapTest,Reservation)772 TEST_F(MemMapTest, Reservation) {
773   CommonInit();
774   std::string error_msg;
775   ScratchFile scratch_file;
776   constexpr size_t kMapSize = 5 * kPageSize;
777   std::unique_ptr<uint8_t[]> data(new uint8_t[kMapSize]());
778   ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
779 
780   MemMap reservation = MemMap::MapAnonymous("Test reservation",
781                                             kMapSize,
782                                             PROT_NONE,
783                                             /*low_4gb=*/ false,
784                                             &error_msg);
785   ASSERT_TRUE(reservation.IsValid());
786   ASSERT_TRUE(error_msg.empty());
787 
788   // Map first part of the reservation.
789   constexpr size_t kChunk1Size = kPageSize - 1u;
790   static_assert(kChunk1Size < kMapSize, "We want to split the reservation.");
791   uint8_t* addr1 = reservation.Begin();
792   MemMap map1 = MemMap::MapFileAtAddress(addr1,
793                                          /*byte_count=*/ kChunk1Size,
794                                          PROT_READ,
795                                          MAP_PRIVATE,
796                                          scratch_file.GetFd(),
797                                          /*start=*/ 0,
798                                          /*low_4gb=*/ false,
799                                          scratch_file.GetFilename().c_str(),
800                                          /*reuse=*/ false,
801                                          &reservation,
802                                          &error_msg);
803   ASSERT_TRUE(map1.IsValid()) << error_msg;
804   ASSERT_TRUE(error_msg.empty());
805   ASSERT_EQ(map1.Size(), kChunk1Size);
806   ASSERT_EQ(addr1, map1.Begin());
807   ASSERT_TRUE(reservation.IsValid());
808   // Entire pages are taken from the `reservation`.
809   ASSERT_LT(map1.End(), map1.BaseEnd());
810   ASSERT_EQ(map1.BaseEnd(), reservation.Begin());
811 
812   // Map second part as an anonymous mapping.
813   constexpr size_t kChunk2Size = 2 * kPageSize;
814   DCHECK_LT(kChunk2Size, reservation.Size());  // We want to split the reservation.
815   uint8_t* addr2 = reservation.Begin();
816   MemMap map2 = MemMap::MapAnonymous("MiddleReservation",
817                                      addr2,
818                                      /*byte_count=*/ kChunk2Size,
819                                      PROT_READ,
820                                      /*low_4gb=*/ false,
821                                      /*reuse=*/ false,
822                                      &reservation,
823                                      &error_msg);
824   ASSERT_TRUE(map2.IsValid()) << error_msg;
825   ASSERT_TRUE(error_msg.empty());
826   ASSERT_EQ(map2.Size(), kChunk2Size);
827   ASSERT_EQ(addr2, map2.Begin());
828   ASSERT_EQ(map2.End(), map2.BaseEnd());  // kChunk2Size is page aligned.
829   ASSERT_EQ(map2.BaseEnd(), reservation.Begin());
830 
831   // Map the rest of the reservation except the last byte.
832   const size_t kChunk3Size = reservation.Size() - 1u;
833   uint8_t* addr3 = reservation.Begin();
834   MemMap map3 = MemMap::MapFileAtAddress(addr3,
835                                          /*byte_count=*/ kChunk3Size,
836                                          PROT_READ,
837                                          MAP_PRIVATE,
838                                          scratch_file.GetFd(),
839                                          /*start=*/ dchecked_integral_cast<size_t>(addr3 - addr1),
840                                          /*low_4gb=*/ false,
841                                          scratch_file.GetFilename().c_str(),
842                                          /*reuse=*/ false,
843                                          &reservation,
844                                          &error_msg);
845   ASSERT_TRUE(map3.IsValid()) << error_msg;
846   ASSERT_TRUE(error_msg.empty());
847   ASSERT_EQ(map3.Size(), kChunk3Size);
848   ASSERT_EQ(addr3, map3.Begin());
849   // Entire pages are taken from the `reservation`, so it's now exhausted.
850   ASSERT_FALSE(reservation.IsValid());
851 
852   // Now split the MiddleReservation.
853   constexpr size_t kChunk2ASize = kPageSize - 1u;
854   DCHECK_LT(kChunk2ASize, map2.Size());  // We want to split the reservation.
855   MemMap map2a = map2.TakeReservedMemory(kChunk2ASize);
856   ASSERT_TRUE(map2a.IsValid()) << error_msg;
857   ASSERT_TRUE(error_msg.empty());
858   ASSERT_EQ(map2a.Size(), kChunk2ASize);
859   ASSERT_EQ(addr2, map2a.Begin());
860   ASSERT_TRUE(map2.IsValid());
861   ASSERT_LT(map2a.End(), map2a.BaseEnd());
862   ASSERT_EQ(map2a.BaseEnd(), map2.Begin());
863 
864   // And take the rest of the middle reservation.
865   const size_t kChunk2BSize = map2.Size() - 1u;
866   uint8_t* addr2b = map2.Begin();
867   MemMap map2b = map2.TakeReservedMemory(kChunk2BSize);
868   ASSERT_TRUE(map2b.IsValid()) << error_msg;
869   ASSERT_TRUE(error_msg.empty());
870   ASSERT_EQ(map2b.Size(), kChunk2ASize);
871   ASSERT_EQ(addr2b, map2b.Begin());
872   ASSERT_FALSE(map2.IsValid());
873 }
874 
875 }  // namespace art
876 
877 namespace {
878 
879 class DumpMapsOnFailListener : public testing::EmptyTestEventListener {
OnTestPartResult(const testing::TestPartResult & result)880   void OnTestPartResult(const testing::TestPartResult& result) override {
881     switch (result.type()) {
882       case testing::TestPartResult::kFatalFailure:
883         art::PrintFileToLog("/proc/self/maps", android::base::LogSeverity::ERROR);
884         break;
885 
886       // TODO: Could consider logging on EXPECT failures.
887       case testing::TestPartResult::kNonFatalFailure:
888       case testing::TestPartResult::kSkip:
889       case testing::TestPartResult::kSuccess:
890         break;
891     }
892   }
893 };
894 
895 }  // namespace
896 
897 // Inject our listener into the test runner.
898 extern "C"
899 __attribute__((visibility("default"))) __attribute__((used))
ArtTestGlobalInit()900 void ArtTestGlobalInit() {
901   testing::UnitTest::GetInstance()->listeners().Append(new DumpMapsOnFailListener());
902 }
903