blob: 14a72b9b1bfff3a050e3a1b2caa8efb4b26e02fc [file] [log] [blame]
Brian Carlstrom9004cb62013-07-26 15:48:31 -07001/*
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
Ian Rogers700a4022014-05-19 16:49:03 -070019#include <memory>
20
Andreas Gampe928f72b2014-09-09 19:53:48 -070021#include <valgrind.h>
22
Brian Carlstrom9004cb62013-07-26 15:48:31 -070023#include "gtest/gtest.h"
24
25namespace art {
26
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -070027class MemMapTest : public testing::Test {
28 public:
Ian Rogers13735952014-10-08 12:43:28 -070029 static uint8_t* BaseBegin(MemMap* mem_map) {
30 return reinterpret_cast<uint8_t*>(mem_map->base_begin_);
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -070031 }
Ian Rogersef7d42f2014-01-06 12:55:46 -080032 static size_t BaseSize(MemMap* mem_map) {
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -070033 return mem_map->base_size_;
34 }
Ian Rogersef7d42f2014-01-06 12:55:46 -080035
36 static void RemapAtEndTest(bool low_4gb) {
37 std::string error_msg;
38 // Cast the page size to size_t.
39 const size_t page_size = static_cast<size_t>(kPageSize);
40 // Map a two-page memory region.
41 MemMap* m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0",
42 nullptr,
43 2 * page_size,
44 PROT_READ | PROT_WRITE,
45 low_4gb,
46 &error_msg);
47 // Check its state and write to it.
Ian Rogers13735952014-10-08 12:43:28 -070048 uint8_t* base0 = m0->Begin();
Ian Rogersef7d42f2014-01-06 12:55:46 -080049 ASSERT_TRUE(base0 != nullptr) << error_msg;
50 size_t size0 = m0->Size();
51 EXPECT_EQ(m0->Size(), 2 * page_size);
52 EXPECT_EQ(BaseBegin(m0), base0);
53 EXPECT_EQ(BaseSize(m0), size0);
54 memset(base0, 42, 2 * page_size);
55 // Remap the latter half into a second MemMap.
56 MemMap* m1 = m0->RemapAtEnd(base0 + page_size,
57 "MemMapTest_RemapAtEndTest_map1",
58 PROT_READ | PROT_WRITE,
59 &error_msg);
60 // Check the states of the two maps.
61 EXPECT_EQ(m0->Begin(), base0) << error_msg;
62 EXPECT_EQ(m0->Size(), page_size);
63 EXPECT_EQ(BaseBegin(m0), base0);
64 EXPECT_EQ(BaseSize(m0), page_size);
Ian Rogers13735952014-10-08 12:43:28 -070065 uint8_t* base1 = m1->Begin();
Ian Rogersef7d42f2014-01-06 12:55:46 -080066 size_t size1 = m1->Size();
67 EXPECT_EQ(base1, base0 + page_size);
68 EXPECT_EQ(size1, page_size);
69 EXPECT_EQ(BaseBegin(m1), base1);
70 EXPECT_EQ(BaseSize(m1), size1);
71 // Write to the second region.
72 memset(base1, 43, page_size);
73 // Check the contents of the two regions.
74 for (size_t i = 0; i < page_size; ++i) {
75 EXPECT_EQ(base0[i], 42);
76 }
77 for (size_t i = 0; i < page_size; ++i) {
78 EXPECT_EQ(base1[i], 43);
79 }
80 // Unmap the first region.
81 delete m0;
82 // Make sure the second region is still accessible after the first
83 // region is unmapped.
84 for (size_t i = 0; i < page_size; ++i) {
85 EXPECT_EQ(base1[i], 43);
86 }
87 delete m1;
88 }
Andreas Gamped8f26db2014-05-19 17:01:13 -070089
Mathieu Chartier6e88ef62014-10-14 15:01:24 -070090 void CommonInit() {
91 MemMap::Init();
92 }
93
Andreas Gamped8f26db2014-05-19 17:01:13 -070094#if defined(__LP64__) && !defined(__x86_64__)
95 static uintptr_t GetLinearScanPos() {
96 return MemMap::next_mem_pos_;
97 }
98#endif
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -070099};
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700100
Andreas Gamped8f26db2014-05-19 17:01:13 -0700101#if defined(__LP64__) && !defined(__x86_64__)
102
103#ifdef __BIONIC__
104extern uintptr_t CreateStartPos(uint64_t input);
105#endif
106
107TEST_F(MemMapTest, Start) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700108 CommonInit();
Andreas Gamped8f26db2014-05-19 17:01:13 -0700109 uintptr_t start = GetLinearScanPos();
110 EXPECT_LE(64 * KB, start);
111 EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS));
Andreas Gamped8f26db2014-05-19 17:01:13 -0700112#ifdef __BIONIC__
113 // Test a couple of values. Make sure they are different.
114 uintptr_t last = 0;
115 for (size_t i = 0; i < 100; ++i) {
116 uintptr_t random_start = CreateStartPos(i * kPageSize);
117 EXPECT_NE(last, random_start);
118 last = random_start;
119 }
120
121 // Even on max, should be below ART_BASE_ADDRESS.
122 EXPECT_LT(CreateStartPos(~0), static_cast<uintptr_t>(ART_BASE_ADDRESS));
123#endif
124 // End of test.
125}
126#endif
127
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700128TEST_F(MemMapTest, MapAnonymousEmpty) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700129 CommonInit();
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700130 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700131 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
Ian Rogersef7d42f2014-01-06 12:55:46 -0800132 nullptr,
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700133 0,
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700134 PROT_READ,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800135 false,
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700136 &error_msg));
Ian Rogersef7d42f2014-01-06 12:55:46 -0800137 ASSERT_TRUE(map.get() != nullptr) << error_msg;
138 ASSERT_TRUE(error_msg.empty());
139 map.reset(MemMap::MapAnonymous("MapAnonymousEmpty",
140 nullptr,
141 kPageSize,
142 PROT_READ | PROT_WRITE,
143 false,
144 &error_msg));
145 ASSERT_TRUE(map.get() != nullptr) << error_msg;
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700146 ASSERT_TRUE(error_msg.empty());
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700147}
148
Ian Rogersef7d42f2014-01-06 12:55:46 -0800149#ifdef __LP64__
150TEST_F(MemMapTest, MapAnonymousEmpty32bit) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700151 CommonInit();
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700152 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700153 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
Ian Rogersef7d42f2014-01-06 12:55:46 -0800154 nullptr,
155 kPageSize,
156 PROT_READ | PROT_WRITE,
157 true,
158 &error_msg));
159 ASSERT_TRUE(map.get() != nullptr) << error_msg;
160 ASSERT_TRUE(error_msg.empty());
161 ASSERT_LT(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 1ULL << 32);
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700162}
Ian Rogersef7d42f2014-01-06 12:55:46 -0800163#endif
164
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700165TEST_F(MemMapTest, MapAnonymousExactAddr) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700166 CommonInit();
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700167 std::string error_msg;
168 // Map at an address that should work, which should succeed.
Ian Rogers700a4022014-05-19 16:49:03 -0700169 std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
Ian Rogers13735952014-10-08 12:43:28 -0700170 reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS),
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700171 kPageSize,
172 PROT_READ | PROT_WRITE,
173 false,
174 &error_msg));
175 ASSERT_TRUE(map0.get() != nullptr) << error_msg;
176 ASSERT_TRUE(error_msg.empty());
177 ASSERT_TRUE(map0->BaseBegin() == reinterpret_cast<void*>(ART_BASE_ADDRESS));
178 // Map at an unspecified address, which should succeed.
Ian Rogers700a4022014-05-19 16:49:03 -0700179 std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1",
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700180 nullptr,
181 kPageSize,
182 PROT_READ | PROT_WRITE,
183 false,
184 &error_msg));
185 ASSERT_TRUE(map1.get() != nullptr) << error_msg;
186 ASSERT_TRUE(error_msg.empty());
187 ASSERT_TRUE(map1->BaseBegin() != nullptr);
188 // Attempt to map at the same address, which should fail.
Ian Rogers700a4022014-05-19 16:49:03 -0700189 std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
Ian Rogers13735952014-10-08 12:43:28 -0700190 reinterpret_cast<uint8_t*>(map1->BaseBegin()),
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700191 kPageSize,
192 PROT_READ | PROT_WRITE,
193 false,
194 &error_msg));
195 ASSERT_TRUE(map2.get() == nullptr) << error_msg;
196 ASSERT_TRUE(!error_msg.empty());
197}
198
Ian Rogersef7d42f2014-01-06 12:55:46 -0800199TEST_F(MemMapTest, RemapAtEnd) {
200 RemapAtEndTest(false);
201}
202
203#ifdef __LP64__
204TEST_F(MemMapTest, RemapAtEnd32bit) {
205 RemapAtEndTest(true);
206}
207#endif
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700208
Qiming Shi84d49cc2014-04-24 15:38:41 +0800209TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700210 CommonInit();
Andreas Gampe928f72b2014-09-09 19:53:48 -0700211 // This test may not work under valgrind.
212 if (RUNNING_ON_VALGRIND == 0) {
213 uintptr_t start_addr = ART_BASE_ADDRESS + 0x1000000;
214 std::string error_msg;
215 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
Ian Rogers13735952014-10-08 12:43:28 -0700216 reinterpret_cast<uint8_t*>(start_addr),
Andreas Gampe928f72b2014-09-09 19:53:48 -0700217 0x21000000,
218 PROT_READ | PROT_WRITE,
219 true,
220 &error_msg));
221 ASSERT_TRUE(map.get() != nullptr) << error_msg;
222 ASSERT_TRUE(error_msg.empty());
223 ASSERT_EQ(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), start_addr);
224 }
Qiming Shi84d49cc2014-04-24 15:38:41 +0800225}
226
227TEST_F(MemMapTest, MapAnonymousOverflow) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700228 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800229 std::string error_msg;
230 uintptr_t ptr = 0;
231 ptr -= kPageSize; // Now it's close to the top.
Ian Rogers700a4022014-05-19 16:49:03 -0700232 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousOverflow",
Ian Rogers13735952014-10-08 12:43:28 -0700233 reinterpret_cast<uint8_t*>(ptr),
Qiming Shi84d49cc2014-04-24 15:38:41 +0800234 2 * kPageSize, // brings it over the top.
235 PROT_READ | PROT_WRITE,
236 false,
237 &error_msg));
238 ASSERT_EQ(nullptr, map.get());
239 ASSERT_FALSE(error_msg.empty());
240}
241
242#ifdef __LP64__
243TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700244 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800245 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700246 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
Ian Rogers13735952014-10-08 12:43:28 -0700247 reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
Qiming Shi84d49cc2014-04-24 15:38:41 +0800248 kPageSize,
249 PROT_READ | PROT_WRITE,
250 true,
251 &error_msg));
252 ASSERT_EQ(nullptr, map.get());
253 ASSERT_FALSE(error_msg.empty());
254}
255
256TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700257 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800258 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700259 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
Ian Rogers13735952014-10-08 12:43:28 -0700260 reinterpret_cast<uint8_t*>(0xF0000000),
Qiming Shi84d49cc2014-04-24 15:38:41 +0800261 0x20000000,
262 PROT_READ | PROT_WRITE,
263 true,
264 &error_msg));
265 ASSERT_EQ(nullptr, map.get());
266 ASSERT_FALSE(error_msg.empty());
267}
268#endif
269
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700270TEST_F(MemMapTest, CheckNoGaps) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700271 CommonInit();
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700272 std::string error_msg;
273 constexpr size_t kNumPages = 3;
274 // Map a 3-page mem map.
275 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymous0",
276 nullptr,
277 kPageSize * kNumPages,
278 PROT_READ | PROT_WRITE,
279 false,
280 &error_msg));
281 ASSERT_TRUE(map.get() != nullptr) << error_msg;
282 ASSERT_TRUE(error_msg.empty());
283 // Record the base address.
Ian Rogers13735952014-10-08 12:43:28 -0700284 uint8_t* map_base = reinterpret_cast<uint8_t*>(map->BaseBegin());
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700285 // Unmap it.
286 map.reset();
287
288 // Map at the same address, but in page-sized separate mem maps,
289 // assuming the space at the address is still available.
290 std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
291 map_base,
292 kPageSize,
293 PROT_READ | PROT_WRITE,
294 false,
295 &error_msg));
296 ASSERT_TRUE(map0.get() != nullptr) << error_msg;
297 ASSERT_TRUE(error_msg.empty());
298 std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1",
299 map_base + kPageSize,
300 kPageSize,
301 PROT_READ | PROT_WRITE,
302 false,
303 &error_msg));
304 ASSERT_TRUE(map1.get() != nullptr) << error_msg;
305 ASSERT_TRUE(error_msg.empty());
306 std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
307 map_base + kPageSize * 2,
308 kPageSize,
309 PROT_READ | PROT_WRITE,
310 false,
311 &error_msg));
312 ASSERT_TRUE(map2.get() != nullptr) << error_msg;
313 ASSERT_TRUE(error_msg.empty());
314
315 // One-map cases.
316 ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map0.get()));
317 ASSERT_TRUE(MemMap::CheckNoGaps(map1.get(), map1.get()));
318 ASSERT_TRUE(MemMap::CheckNoGaps(map2.get(), map2.get()));
319
320 // Two or three-map cases.
321 ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map1.get()));
322 ASSERT_TRUE(MemMap::CheckNoGaps(map1.get(), map2.get()));
323 ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map2.get()));
324
325 // Unmap the middle one.
326 map1.reset();
327
328 // Should return false now that there's a gap in the middle.
329 ASSERT_FALSE(MemMap::CheckNoGaps(map0.get(), map2.get()));
330}
331
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700332} // namespace art