Home | History | Annotate | Download | only in runtime
      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 
     21 #include "gtest/gtest.h"
     22 
     23 namespace art {
     24 
     25 class MemMapTest : public testing::Test {
     26  public:
     27   static byte* BaseBegin(MemMap* mem_map) {
     28     return reinterpret_cast<byte*>(mem_map->base_begin_);
     29   }
     30   static size_t BaseSize(MemMap* mem_map) {
     31     return mem_map->base_size_;
     32   }
     33 
     34   static void RemapAtEndTest(bool low_4gb) {
     35     std::string error_msg;
     36     // Cast the page size to size_t.
     37     const size_t page_size = static_cast<size_t>(kPageSize);
     38     // Map a two-page memory region.
     39     MemMap* m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0",
     40                                       nullptr,
     41                                       2 * page_size,
     42                                       PROT_READ | PROT_WRITE,
     43                                       low_4gb,
     44                                       &error_msg);
     45     // Check its state and write to it.
     46     byte* base0 = m0->Begin();
     47     ASSERT_TRUE(base0 != nullptr) << error_msg;
     48     size_t size0 = m0->Size();
     49     EXPECT_EQ(m0->Size(), 2 * page_size);
     50     EXPECT_EQ(BaseBegin(m0), base0);
     51     EXPECT_EQ(BaseSize(m0), size0);
     52     memset(base0, 42, 2 * page_size);
     53     // Remap the latter half into a second MemMap.
     54     MemMap* m1 = m0->RemapAtEnd(base0 + page_size,
     55                                 "MemMapTest_RemapAtEndTest_map1",
     56                                 PROT_READ | PROT_WRITE,
     57                                 &error_msg);
     58     // Check the states of the two maps.
     59     EXPECT_EQ(m0->Begin(), base0) << error_msg;
     60     EXPECT_EQ(m0->Size(), page_size);
     61     EXPECT_EQ(BaseBegin(m0), base0);
     62     EXPECT_EQ(BaseSize(m0), page_size);
     63     byte* base1 = m1->Begin();
     64     size_t size1 = m1->Size();
     65     EXPECT_EQ(base1, base0 + page_size);
     66     EXPECT_EQ(size1, page_size);
     67     EXPECT_EQ(BaseBegin(m1), base1);
     68     EXPECT_EQ(BaseSize(m1), size1);
     69     // Write to the second region.
     70     memset(base1, 43, page_size);
     71     // Check the contents of the two regions.
     72     for (size_t i = 0; i < page_size; ++i) {
     73       EXPECT_EQ(base0[i], 42);
     74     }
     75     for (size_t i = 0; i < page_size; ++i) {
     76       EXPECT_EQ(base1[i], 43);
     77     }
     78     // Unmap the first region.
     79     delete m0;
     80     // Make sure the second region is still accessible after the first
     81     // region is unmapped.
     82     for (size_t i = 0; i < page_size; ++i) {
     83       EXPECT_EQ(base1[i], 43);
     84     }
     85     delete m1;
     86   }
     87 
     88   void CommonInit() {
     89     MemMap::Init();
     90   }
     91 
     92 #if defined(__LP64__) && !defined(__x86_64__)
     93   static uintptr_t GetLinearScanPos() {
     94     return MemMap::next_mem_pos_;
     95   }
     96 #endif
     97 };
     98 
     99 #if defined(__LP64__) && !defined(__x86_64__)
    100 
    101 #ifdef __BIONIC__
    102 extern uintptr_t CreateStartPos(uint64_t input);
    103 #endif
    104 
    105 TEST_F(MemMapTest, Start) {
    106   CommonInit();
    107   uintptr_t start = GetLinearScanPos();
    108   EXPECT_LE(64 * KB, start);
    109   EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS));
    110 #ifdef __BIONIC__
    111   // Test a couple of values. Make sure they are different.
    112   uintptr_t last = 0;
    113   for (size_t i = 0; i < 100; ++i) {
    114     uintptr_t random_start = CreateStartPos(i * kPageSize);
    115     EXPECT_NE(last, random_start);
    116     last = random_start;
    117   }
    118 
    119   // Even on max, should be below ART_BASE_ADDRESS.
    120   EXPECT_LT(CreateStartPos(~0), static_cast<uintptr_t>(ART_BASE_ADDRESS));
    121 #endif
    122   // End of test.
    123 }
    124 #endif
    125 
    126 TEST_F(MemMapTest, MapAnonymousEmpty) {
    127   CommonInit();
    128   std::string error_msg;
    129   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
    130                                              nullptr,
    131                                              0,
    132                                              PROT_READ,
    133                                              false,
    134                                              &error_msg));
    135   ASSERT_TRUE(map.get() != nullptr) << error_msg;
    136   ASSERT_TRUE(error_msg.empty());
    137   map.reset(MemMap::MapAnonymous("MapAnonymousEmpty",
    138                                  nullptr,
    139                                  kPageSize,
    140                                  PROT_READ | PROT_WRITE,
    141                                  false,
    142                                  &error_msg));
    143   ASSERT_TRUE(map.get() != nullptr) << error_msg;
    144   ASSERT_TRUE(error_msg.empty());
    145 }
    146 
    147 #ifdef __LP64__
    148 TEST_F(MemMapTest, MapAnonymousEmpty32bit) {
    149   CommonInit();
    150   std::string error_msg;
    151   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
    152                                              nullptr,
    153                                              kPageSize,
    154                                              PROT_READ | PROT_WRITE,
    155                                              true,
    156                                              &error_msg));
    157   ASSERT_TRUE(map.get() != nullptr) << error_msg;
    158   ASSERT_TRUE(error_msg.empty());
    159   ASSERT_LT(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 1ULL << 32);
    160 }
    161 #endif
    162 
    163 TEST_F(MemMapTest, MapAnonymousExactAddr) {
    164   CommonInit();
    165   std::string error_msg;
    166   // Map at an address that should work, which should succeed.
    167   std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
    168                                               reinterpret_cast<byte*>(ART_BASE_ADDRESS),
    169                                               kPageSize,
    170                                               PROT_READ | PROT_WRITE,
    171                                               false,
    172                                               &error_msg));
    173   ASSERT_TRUE(map0.get() != nullptr) << error_msg;
    174   ASSERT_TRUE(error_msg.empty());
    175   ASSERT_TRUE(map0->BaseBegin() == reinterpret_cast<void*>(ART_BASE_ADDRESS));
    176   // Map at an unspecified address, which should succeed.
    177   std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1",
    178                                               nullptr,
    179                                               kPageSize,
    180                                               PROT_READ | PROT_WRITE,
    181                                               false,
    182                                               &error_msg));
    183   ASSERT_TRUE(map1.get() != nullptr) << error_msg;
    184   ASSERT_TRUE(error_msg.empty());
    185   ASSERT_TRUE(map1->BaseBegin() != nullptr);
    186   // Attempt to map at the same address, which should fail.
    187   std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
    188                                               reinterpret_cast<byte*>(map1->BaseBegin()),
    189                                               kPageSize,
    190                                               PROT_READ | PROT_WRITE,
    191                                               false,
    192                                               &error_msg));
    193   ASSERT_TRUE(map2.get() == nullptr) << error_msg;
    194   ASSERT_TRUE(!error_msg.empty());
    195 }
    196 
    197 TEST_F(MemMapTest, RemapAtEnd) {
    198   RemapAtEndTest(false);
    199 }
    200 
    201 #ifdef __LP64__
    202 TEST_F(MemMapTest, RemapAtEnd32bit) {
    203   RemapAtEndTest(true);
    204 }
    205 #endif
    206 
    207 TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
    208   uintptr_t start_addr = ART_BASE_ADDRESS + 0x1000000;
    209   std::string error_msg;
    210   CommonInit();
    211   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
    212                                              reinterpret_cast<byte*>(start_addr),
    213                                              0x21000000,
    214                                              PROT_READ | PROT_WRITE,
    215                                              true,
    216                                              &error_msg));
    217   ASSERT_TRUE(map.get() != nullptr) << error_msg;
    218   ASSERT_TRUE(error_msg.empty());
    219   ASSERT_EQ(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), start_addr);
    220 }
    221 
    222 TEST_F(MemMapTest, MapAnonymousOverflow) {
    223   CommonInit();
    224   std::string error_msg;
    225   uintptr_t ptr = 0;
    226   ptr -= kPageSize;  // Now it's close to the top.
    227   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousOverflow",
    228                                              reinterpret_cast<byte*>(ptr),
    229                                              2 * kPageSize,  // brings it over the top.
    230                                              PROT_READ | PROT_WRITE,
    231                                              false,
    232                                              &error_msg));
    233   ASSERT_EQ(nullptr, map.get());
    234   ASSERT_FALSE(error_msg.empty());
    235 }
    236 
    237 #ifdef __LP64__
    238 TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
    239   CommonInit();
    240   std::string error_msg;
    241   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
    242                                              reinterpret_cast<byte*>(UINT64_C(0x100000000)),
    243                                              kPageSize,
    244                                              PROT_READ | PROT_WRITE,
    245                                              true,
    246                                              &error_msg));
    247   ASSERT_EQ(nullptr, map.get());
    248   ASSERT_FALSE(error_msg.empty());
    249 }
    250 
    251 TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
    252   CommonInit();
    253   std::string error_msg;
    254   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
    255                                              reinterpret_cast<byte*>(0xF0000000),
    256                                              0x20000000,
    257                                              PROT_READ | PROT_WRITE,
    258                                              true,
    259                                              &error_msg));
    260   ASSERT_EQ(nullptr, map.get());
    261   ASSERT_FALSE(error_msg.empty());
    262 }
    263 #endif
    264 
    265 TEST_F(MemMapTest, CheckNoGaps) {
    266   CommonInit();
    267   std::string error_msg;
    268   constexpr size_t kNumPages = 3;
    269   // Map a 3-page mem map.
    270   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymous0",
    271                                                    nullptr,
    272                                                    kPageSize * kNumPages,
    273                                                    PROT_READ | PROT_WRITE,
    274                                                    false,
    275                                                    &error_msg));
    276   ASSERT_TRUE(map.get() != nullptr) << error_msg;
    277   ASSERT_TRUE(error_msg.empty());
    278   // Record the base address.
    279   byte* map_base = reinterpret_cast<byte*>(map->BaseBegin());
    280   // Unmap it.
    281   map.reset();
    282 
    283   // Map at the same address, but in page-sized separate mem maps,
    284   // assuming the space at the address is still available.
    285   std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
    286                                                     map_base,
    287                                                     kPageSize,
    288                                                     PROT_READ | PROT_WRITE,
    289                                                     false,
    290                                                     &error_msg));
    291   ASSERT_TRUE(map0.get() != nullptr) << error_msg;
    292   ASSERT_TRUE(error_msg.empty());
    293   std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1",
    294                                                     map_base + kPageSize,
    295                                                     kPageSize,
    296                                                     PROT_READ | PROT_WRITE,
    297                                                     false,
    298                                                     &error_msg));
    299   ASSERT_TRUE(map1.get() != nullptr) << error_msg;
    300   ASSERT_TRUE(error_msg.empty());
    301   std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
    302                                                     map_base + kPageSize * 2,
    303                                                     kPageSize,
    304                                                     PROT_READ | PROT_WRITE,
    305                                                     false,
    306                                                     &error_msg));
    307   ASSERT_TRUE(map2.get() != nullptr) << error_msg;
    308   ASSERT_TRUE(error_msg.empty());
    309 
    310   // One-map cases.
    311   ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map0.get()));
    312   ASSERT_TRUE(MemMap::CheckNoGaps(map1.get(), map1.get()));
    313   ASSERT_TRUE(MemMap::CheckNoGaps(map2.get(), map2.get()));
    314 
    315   // Two or three-map cases.
    316   ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map1.get()));
    317   ASSERT_TRUE(MemMap::CheckNoGaps(map1.get(), map2.get()));
    318   ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map2.get()));
    319 
    320   // Unmap the middle one.
    321   map1.reset();
    322 
    323   // Should return false now that there's a gap in the middle.
    324   ASSERT_FALSE(MemMap::CheckNoGaps(map0.get(), map2.get()));
    325 }
    326 
    327 }  // namespace art
    328