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:
BaseBegin(MemMap * mem_map)27 static byte* BaseBegin(MemMap* mem_map) {
28 return reinterpret_cast<byte*>(mem_map->base_begin_);
29 }
BaseSize(MemMap * mem_map)30 static size_t BaseSize(MemMap* mem_map) {
31 return mem_map->base_size_;
32 }
33
RemapAtEndTest(bool low_4gb)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
CommonInit()88 void CommonInit() {
89 MemMap::Init();
90 }
91
92 #if defined(__LP64__) && !defined(__x86_64__)
GetLinearScanPos()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
TEST_F(MemMapTest,Start)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
TEST_F(MemMapTest,MapAnonymousEmpty)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__
TEST_F(MemMapTest,MapAnonymousEmpty32bit)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
TEST_F(MemMapTest,MapAnonymousExactAddr)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
TEST_F(MemMapTest,RemapAtEnd)197 TEST_F(MemMapTest, RemapAtEnd) {
198 RemapAtEndTest(false);
199 }
200
201 #ifdef __LP64__
TEST_F(MemMapTest,RemapAtEnd32bit)202 TEST_F(MemMapTest, RemapAtEnd32bit) {
203 RemapAtEndTest(true);
204 }
205 #endif
206
TEST_F(MemMapTest,MapAnonymousExactAddr32bitHighAddr)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
TEST_F(MemMapTest,MapAnonymousOverflow)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__
TEST_F(MemMapTest,MapAnonymousLow4GBExpectedTooHigh)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
TEST_F(MemMapTest,MapAnonymousLow4GBRangeTooHigh)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
TEST_F(MemMapTest,CheckNoGaps)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