blob: 3790e53fe332342bb3e9308f8ac2e99e0d3a2eaf [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
Mathieu Chartier42bddce2015-11-09 15:16:56 -080021#include "common_runtime_test.h"
Evgenii Stepanov1e133742015-05-20 12:30:59 -070022#include "base/memory_tool.h"
Mathieu Chartier42bddce2015-11-09 15:16:56 -080023#include "base/unix_file/fd_file.h"
Brian Carlstrom9004cb62013-07-26 15:48:31 -070024
25namespace art {
26
Mathieu Chartier42bddce2015-11-09 15:16:56 -080027class MemMapTest : public CommonRuntimeTest {
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -070028 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,
Vladimir Marko5c42c292015-02-25 12:02:49 +000046 false,
Ian Rogersef7d42f2014-01-06 12:55:46 -080047 &error_msg);
48 // Check its state and write to it.
Ian Rogers13735952014-10-08 12:43:28 -070049 uint8_t* base0 = m0->Begin();
Ian Rogersef7d42f2014-01-06 12:55:46 -080050 ASSERT_TRUE(base0 != nullptr) << error_msg;
51 size_t size0 = m0->Size();
52 EXPECT_EQ(m0->Size(), 2 * page_size);
53 EXPECT_EQ(BaseBegin(m0), base0);
54 EXPECT_EQ(BaseSize(m0), size0);
55 memset(base0, 42, 2 * page_size);
56 // Remap the latter half into a second MemMap.
57 MemMap* m1 = m0->RemapAtEnd(base0 + page_size,
58 "MemMapTest_RemapAtEndTest_map1",
59 PROT_READ | PROT_WRITE,
60 &error_msg);
61 // Check the states of the two maps.
62 EXPECT_EQ(m0->Begin(), base0) << error_msg;
63 EXPECT_EQ(m0->Size(), page_size);
64 EXPECT_EQ(BaseBegin(m0), base0);
65 EXPECT_EQ(BaseSize(m0), page_size);
Ian Rogers13735952014-10-08 12:43:28 -070066 uint8_t* base1 = m1->Begin();
Ian Rogersef7d42f2014-01-06 12:55:46 -080067 size_t size1 = m1->Size();
68 EXPECT_EQ(base1, base0 + page_size);
69 EXPECT_EQ(size1, page_size);
70 EXPECT_EQ(BaseBegin(m1), base1);
71 EXPECT_EQ(BaseSize(m1), size1);
72 // Write to the second region.
73 memset(base1, 43, page_size);
74 // Check the contents of the two regions.
75 for (size_t i = 0; i < page_size; ++i) {
76 EXPECT_EQ(base0[i], 42);
77 }
78 for (size_t i = 0; i < page_size; ++i) {
79 EXPECT_EQ(base1[i], 43);
80 }
81 // Unmap the first region.
82 delete m0;
83 // Make sure the second region is still accessible after the first
84 // region is unmapped.
85 for (size_t i = 0; i < page_size; ++i) {
86 EXPECT_EQ(base1[i], 43);
87 }
88 delete m1;
89 }
Andreas Gamped8f26db2014-05-19 17:01:13 -070090
Mathieu Chartier6e88ef62014-10-14 15:01:24 -070091 void CommonInit() {
92 MemMap::Init();
93 }
94
Andreas Gamped8f26db2014-05-19 17:01:13 -070095#if defined(__LP64__) && !defined(__x86_64__)
96 static uintptr_t GetLinearScanPos() {
97 return MemMap::next_mem_pos_;
98 }
99#endif
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700100};
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700101
Andreas Gamped8f26db2014-05-19 17:01:13 -0700102#if defined(__LP64__) && !defined(__x86_64__)
103
104#ifdef __BIONIC__
105extern uintptr_t CreateStartPos(uint64_t input);
106#endif
107
108TEST_F(MemMapTest, Start) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700109 CommonInit();
Andreas Gamped8f26db2014-05-19 17:01:13 -0700110 uintptr_t start = GetLinearScanPos();
111 EXPECT_LE(64 * KB, start);
112 EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS));
Andreas Gamped8f26db2014-05-19 17:01:13 -0700113#ifdef __BIONIC__
114 // Test a couple of values. Make sure they are different.
115 uintptr_t last = 0;
116 for (size_t i = 0; i < 100; ++i) {
117 uintptr_t random_start = CreateStartPos(i * kPageSize);
118 EXPECT_NE(last, random_start);
119 last = random_start;
120 }
121
122 // Even on max, should be below ART_BASE_ADDRESS.
123 EXPECT_LT(CreateStartPos(~0), static_cast<uintptr_t>(ART_BASE_ADDRESS));
124#endif
125 // End of test.
126}
127#endif
128
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700129TEST_F(MemMapTest, MapAnonymousEmpty) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700130 CommonInit();
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700131 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700132 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000133 nullptr,
134 0,
135 PROT_READ,
136 false,
137 false,
138 &error_msg));
Ian Rogersef7d42f2014-01-06 12:55:46 -0800139 ASSERT_TRUE(map.get() != nullptr) << error_msg;
140 ASSERT_TRUE(error_msg.empty());
141 map.reset(MemMap::MapAnonymous("MapAnonymousEmpty",
142 nullptr,
143 kPageSize,
144 PROT_READ | PROT_WRITE,
145 false,
Vladimir Marko5c42c292015-02-25 12:02:49 +0000146 false,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800147 &error_msg));
148 ASSERT_TRUE(map.get() != nullptr) << error_msg;
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700149 ASSERT_TRUE(error_msg.empty());
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700150}
151
Ian Rogersef7d42f2014-01-06 12:55:46 -0800152#ifdef __LP64__
153TEST_F(MemMapTest, MapAnonymousEmpty32bit) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700154 CommonInit();
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700155 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700156 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000157 nullptr,
158 kPageSize,
159 PROT_READ | PROT_WRITE,
160 true,
161 false,
162 &error_msg));
Ian Rogersef7d42f2014-01-06 12:55:46 -0800163 ASSERT_TRUE(map.get() != nullptr) << error_msg;
164 ASSERT_TRUE(error_msg.empty());
165 ASSERT_LT(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 1ULL << 32);
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700166}
Mathieu Chartier42bddce2015-11-09 15:16:56 -0800167TEST_F(MemMapTest, MapFile32Bit) {
168 CommonInit();
169 std::string error_msg;
170 ScratchFile scratch_file;
171 constexpr size_t kMapSize = kPageSize;
172 std::unique_ptr<uint8_t[]> data(new uint8_t[kMapSize]());
173 ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
174 std::unique_ptr<MemMap> map(MemMap::MapFile(/*byte_count*/kMapSize,
175 PROT_READ,
176 MAP_PRIVATE,
177 scratch_file.GetFd(),
178 /*start*/0,
179 /*low_4gb*/true,
180 scratch_file.GetFilename().c_str(),
181 &error_msg));
182 ASSERT_TRUE(map != nullptr) << error_msg;
183 ASSERT_TRUE(error_msg.empty());
184 ASSERT_EQ(map->Size(), kMapSize);
185 ASSERT_LT(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), 1ULL << 32);
186}
Ian Rogersef7d42f2014-01-06 12:55:46 -0800187#endif
188
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700189TEST_F(MemMapTest, MapAnonymousExactAddr) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700190 CommonInit();
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700191 std::string error_msg;
192 // Map at an address that should work, which should succeed.
Ian Rogers700a4022014-05-19 16:49:03 -0700193 std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000194 reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS),
195 kPageSize,
196 PROT_READ | PROT_WRITE,
197 false,
198 false,
199 &error_msg));
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700200 ASSERT_TRUE(map0.get() != nullptr) << error_msg;
201 ASSERT_TRUE(error_msg.empty());
202 ASSERT_TRUE(map0->BaseBegin() == reinterpret_cast<void*>(ART_BASE_ADDRESS));
203 // Map at an unspecified address, which should succeed.
Ian Rogers700a4022014-05-19 16:49:03 -0700204 std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000205 nullptr,
206 kPageSize,
207 PROT_READ | PROT_WRITE,
208 false,
209 false,
210 &error_msg));
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700211 ASSERT_TRUE(map1.get() != nullptr) << error_msg;
212 ASSERT_TRUE(error_msg.empty());
213 ASSERT_TRUE(map1->BaseBegin() != nullptr);
214 // Attempt to map at the same address, which should fail.
Ian Rogers700a4022014-05-19 16:49:03 -0700215 std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000216 reinterpret_cast<uint8_t*>(map1->BaseBegin()),
217 kPageSize,
218 PROT_READ | PROT_WRITE,
219 false,
220 false,
221 &error_msg));
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700222 ASSERT_TRUE(map2.get() == nullptr) << error_msg;
223 ASSERT_TRUE(!error_msg.empty());
224}
225
Ian Rogersef7d42f2014-01-06 12:55:46 -0800226TEST_F(MemMapTest, RemapAtEnd) {
227 RemapAtEndTest(false);
228}
229
230#ifdef __LP64__
231TEST_F(MemMapTest, RemapAtEnd32bit) {
232 RemapAtEndTest(true);
233}
234#endif
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700235
Qiming Shi84d49cc2014-04-24 15:38:41 +0800236TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700237 CommonInit();
Andreas Gampe928f72b2014-09-09 19:53:48 -0700238 // This test may not work under valgrind.
Evgenii Stepanov1e133742015-05-20 12:30:59 -0700239 if (RUNNING_ON_MEMORY_TOOL == 0) {
Andreas Gampe928f72b2014-09-09 19:53:48 -0700240 uintptr_t start_addr = ART_BASE_ADDRESS + 0x1000000;
241 std::string error_msg;
242 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
Ian Rogers13735952014-10-08 12:43:28 -0700243 reinterpret_cast<uint8_t*>(start_addr),
Andreas Gampe928f72b2014-09-09 19:53:48 -0700244 0x21000000,
245 PROT_READ | PROT_WRITE,
246 true,
Vladimir Marko5c42c292015-02-25 12:02:49 +0000247 false,
Andreas Gampe928f72b2014-09-09 19:53:48 -0700248 &error_msg));
249 ASSERT_TRUE(map.get() != nullptr) << error_msg;
250 ASSERT_TRUE(error_msg.empty());
251 ASSERT_EQ(reinterpret_cast<uintptr_t>(BaseBegin(map.get())), start_addr);
252 }
Qiming Shi84d49cc2014-04-24 15:38:41 +0800253}
254
255TEST_F(MemMapTest, MapAnonymousOverflow) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700256 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800257 std::string error_msg;
258 uintptr_t ptr = 0;
259 ptr -= kPageSize; // Now it's close to the top.
Ian Rogers700a4022014-05-19 16:49:03 -0700260 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousOverflow",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000261 reinterpret_cast<uint8_t*>(ptr),
262 2 * kPageSize, // brings it over the top.
263 PROT_READ | PROT_WRITE,
264 false,
265 false,
266 &error_msg));
Qiming Shi84d49cc2014-04-24 15:38:41 +0800267 ASSERT_EQ(nullptr, map.get());
268 ASSERT_FALSE(error_msg.empty());
269}
270
271#ifdef __LP64__
272TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700273 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800274 std::string error_msg;
Vladimir Marko5c42c292015-02-25 12:02:49 +0000275 std::unique_ptr<MemMap> map(
276 MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
277 reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
278 kPageSize,
279 PROT_READ | PROT_WRITE,
280 true,
281 false,
282 &error_msg));
Qiming Shi84d49cc2014-04-24 15:38:41 +0800283 ASSERT_EQ(nullptr, map.get());
284 ASSERT_FALSE(error_msg.empty());
285}
286
287TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700288 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800289 std::string error_msg;
Ian Rogers700a4022014-05-19 16:49:03 -0700290 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
Vladimir Marko5c42c292015-02-25 12:02:49 +0000291 reinterpret_cast<uint8_t*>(0xF0000000),
292 0x20000000,
293 PROT_READ | PROT_WRITE,
294 true,
295 false,
296 &error_msg));
Qiming Shi84d49cc2014-04-24 15:38:41 +0800297 ASSERT_EQ(nullptr, map.get());
298 ASSERT_FALSE(error_msg.empty());
299}
300#endif
301
Vladimir Marko5c42c292015-02-25 12:02:49 +0000302TEST_F(MemMapTest, MapAnonymousReuse) {
303 CommonInit();
304 std::string error_msg;
305 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousReserve",
306 nullptr,
307 0x20000,
308 PROT_READ | PROT_WRITE,
309 false,
310 false,
311 &error_msg));
312 ASSERT_NE(nullptr, map.get());
313 ASSERT_TRUE(error_msg.empty());
314 std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymousReused",
315 reinterpret_cast<uint8_t*>(map->BaseBegin()),
316 0x10000,
317 PROT_READ | PROT_WRITE,
318 false,
319 true,
320 &error_msg));
321 ASSERT_NE(nullptr, map2.get());
322 ASSERT_TRUE(error_msg.empty());
323}
324
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700325TEST_F(MemMapTest, CheckNoGaps) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700326 CommonInit();
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700327 std::string error_msg;
328 constexpr size_t kNumPages = 3;
329 // Map a 3-page mem map.
330 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymous0",
331 nullptr,
332 kPageSize * kNumPages,
333 PROT_READ | PROT_WRITE,
334 false,
Vladimir Marko5c42c292015-02-25 12:02:49 +0000335 false,
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700336 &error_msg));
337 ASSERT_TRUE(map.get() != nullptr) << error_msg;
338 ASSERT_TRUE(error_msg.empty());
339 // Record the base address.
Ian Rogers13735952014-10-08 12:43:28 -0700340 uint8_t* map_base = reinterpret_cast<uint8_t*>(map->BaseBegin());
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700341 // Unmap it.
342 map.reset();
343
344 // Map at the same address, but in page-sized separate mem maps,
345 // assuming the space at the address is still available.
346 std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
347 map_base,
348 kPageSize,
349 PROT_READ | PROT_WRITE,
350 false,
Vladimir Marko5c42c292015-02-25 12:02:49 +0000351 false,
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700352 &error_msg));
353 ASSERT_TRUE(map0.get() != nullptr) << error_msg;
354 ASSERT_TRUE(error_msg.empty());
355 std::unique_ptr<MemMap> map1(MemMap::MapAnonymous("MapAnonymous1",
356 map_base + kPageSize,
357 kPageSize,
358 PROT_READ | PROT_WRITE,
359 false,
Vladimir Marko5c42c292015-02-25 12:02:49 +0000360 false,
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700361 &error_msg));
362 ASSERT_TRUE(map1.get() != nullptr) << error_msg;
363 ASSERT_TRUE(error_msg.empty());
364 std::unique_ptr<MemMap> map2(MemMap::MapAnonymous("MapAnonymous2",
365 map_base + kPageSize * 2,
366 kPageSize,
367 PROT_READ | PROT_WRITE,
368 false,
Vladimir Marko5c42c292015-02-25 12:02:49 +0000369 false,
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700370 &error_msg));
371 ASSERT_TRUE(map2.get() != nullptr) << error_msg;
372 ASSERT_TRUE(error_msg.empty());
373
374 // One-map cases.
375 ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map0.get()));
376 ASSERT_TRUE(MemMap::CheckNoGaps(map1.get(), map1.get()));
377 ASSERT_TRUE(MemMap::CheckNoGaps(map2.get(), map2.get()));
378
379 // Two or three-map cases.
380 ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map1.get()));
381 ASSERT_TRUE(MemMap::CheckNoGaps(map1.get(), map2.get()));
382 ASSERT_TRUE(MemMap::CheckNoGaps(map0.get(), map2.get()));
383
384 // Unmap the middle one.
385 map1.reset();
386
387 // Should return false now that there's a gap in the middle.
388 ASSERT_FALSE(MemMap::CheckNoGaps(map0.get(), map2.get()));
389}
390
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700391} // namespace art