blob: 938cff7e97228e7a1fc1b9125c44fcaef0d8f1c2 [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>
Alex Lightca97ada2018-02-02 09:25:31 -080020#include <random>
Ian Rogers700a4022014-05-19 16:49:03 -070021
Andreas Gampec857f4a2018-10-25 13:12:37 -070022#include "common_art_test.h"
David Sehrd5f8de82018-04-27 14:12:03 -070023#include "common_runtime_test.h" // For TEST_DISABLED_FOR_MIPS
Andreas Gampec857f4a2018-10-25 13:12:37 -070024#include "logging.h"
David Sehr1979c642018-04-26 14:41:18 -070025#include "memory_tool.h"
David Sehr10db8fe2018-07-18 11:01:20 -070026#include "mman.h"
David Sehr1979c642018-04-26 14:41:18 -070027#include "unix_file/fd_file.h"
Brian Carlstrom9004cb62013-07-26 15:48:31 -070028
29namespace art {
30
David Sehrd5f8de82018-04-27 14:12:03 -070031class MemMapTest : public CommonArtTest {
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -070032 public:
Alex Lightca97ada2018-02-02 09:25:31 -080033 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
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
Mathieu Chartier16d29f82015-11-10 10:32:52 -080052 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;
Vladimir Markoc34bebf2018-08-16 16:12:49 +010055 MemMap map = MemMap::MapAnonymous("temp",
Vladimir Markoc34bebf2018-08-16 16:12:49 +010056 size,
57 PROT_READ,
58 low_4gb,
Vladimir Markoc34bebf2018-08-16 16:12:49 +010059 &error_msg);
60 CHECK(map.IsValid());
61 return map.Begin();
Mathieu Chartier16d29f82015-11-10 10:32:52 -080062 }
63
Ian Rogersef7d42f2014-01-06 12:55:46 -080064 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.
Vladimir Markoc34bebf2018-08-16 16:12:49 +010069 MemMap m0 = MemMap::MapAnonymous("MemMapTest_RemapAtEndTest_map0",
Vladimir Markoc34bebf2018-08-16 16:12:49 +010070 2 * page_size,
71 PROT_READ | PROT_WRITE,
72 low_4gb,
Vladimir Markoc34bebf2018-08-16 16:12:49 +010073 &error_msg);
Ian Rogersef7d42f2014-01-06 12:55:46 -080074 // Check its state and write to it.
Vladimir Markoc34bebf2018-08-16 16:12:49 +010075 ASSERT_TRUE(m0.IsValid());
76 uint8_t* base0 = m0.Begin();
Ian Rogersef7d42f2014-01-06 12:55:46 -080077 ASSERT_TRUE(base0 != nullptr) << error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +010078 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);
Ian Rogersef7d42f2014-01-06 12:55:46 -080082 memset(base0, 42, 2 * page_size);
83 // Remap the latter half into a second MemMap.
Vladimir Markoc34bebf2018-08-16 16:12:49 +010084 MemMap m1 = m0.RemapAtEnd(base0 + page_size,
85 "MemMapTest_RemapAtEndTest_map1",
86 PROT_READ | PROT_WRITE,
87 &error_msg);
Ian Rogersef7d42f2014-01-06 12:55:46 -080088 // Check the states of the two maps.
Vladimir Markoc34bebf2018-08-16 16:12:49 +010089 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();
Ian Rogersef7d42f2014-01-06 12:55:46 -080095 EXPECT_EQ(base1, base0 + page_size);
96 EXPECT_EQ(size1, page_size);
Vladimir Markoc34bebf2018-08-16 16:12:49 +010097 EXPECT_EQ(m1.BaseBegin(), base1);
98 EXPECT_EQ(m1.BaseSize(), size1);
Ian Rogersef7d42f2014-01-06 12:55:46 -080099 // 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.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100109 m0.Reset();
Ian Rogersef7d42f2014-01-06 12:55:46 -0800110 // 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 }
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100115 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());
Ian Rogersef7d42f2014-01-06 12:55:46 -0800121 }
Andreas Gamped8f26db2014-05-19 17:01:13 -0700122
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700123 void CommonInit() {
124 MemMap::Init();
125 }
126
Andreas Gamped8f26db2014-05-19 17:01:13 -0700127#if defined(__LP64__) && !defined(__x86_64__)
128 static uintptr_t GetLinearScanPos() {
129 return MemMap::next_mem_pos_;
130 }
131#endif
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700132};
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700133
Andreas Gamped8f26db2014-05-19 17:01:13 -0700134#if defined(__LP64__) && !defined(__x86_64__)
135
136#ifdef __BIONIC__
137extern uintptr_t CreateStartPos(uint64_t input);
138#endif
139
140TEST_F(MemMapTest, Start) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700141 CommonInit();
Andreas Gamped8f26db2014-05-19 17:01:13 -0700142 uintptr_t start = GetLinearScanPos();
143 EXPECT_LE(64 * KB, start);
144 EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS));
Andreas Gamped8f26db2014-05-19 17:01:13 -0700145#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
Alex Lightca97ada2018-02-02 09:25:31 -0800161// We need mremap to be able to test ReplaceMapping at all
162#if HAVE_MREMAP_SYSCALL
163TEST_F(MemMapTest, ReplaceMapping_SameSize) {
164 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100165 MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100166 kPageSize,
167 PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100168 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100169 &error_msg);
170 ASSERT_TRUE(dest.IsValid());
171 MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100172 kPageSize,
173 PROT_WRITE | PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100174 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100175 &error_msg);
176 ASSERT_TRUE(source.IsValid());
177 void* source_addr = source.Begin();
178 void* dest_addr = dest.Begin();
Alex Lightca97ada2018-02-02 09:25:31 -0800179 ASSERT_TRUE(IsAddressMapped(source_addr));
180 ASSERT_TRUE(IsAddressMapped(dest_addr));
181
182 std::vector<uint8_t> data = RandomData(kPageSize);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100183 memcpy(source.Begin(), data.data(), data.size());
Alex Lightca97ada2018-02-02 09:25:31 -0800184
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100185 ASSERT_TRUE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
Alex Lightca97ada2018-02-02 09:25:31 -0800186
187 ASSERT_FALSE(IsAddressMapped(source_addr));
188 ASSERT_TRUE(IsAddressMapped(dest_addr));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100189 ASSERT_FALSE(source.IsValid());
Alex Lightca97ada2018-02-02 09:25:31 -0800190
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100191 ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
Alex Lightca97ada2018-02-02 09:25:31 -0800192
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100193 ASSERT_EQ(memcmp(dest.Begin(), data.data(), dest.Size()), 0);
Alex Lightca97ada2018-02-02 09:25:31 -0800194}
195
196TEST_F(MemMapTest, ReplaceMapping_MakeLarger) {
197 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100198 MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100199 5 * kPageSize, // Need to make it larger
200 // initially so we know
201 // there won't be mappings
Vladimir Marko830f3562018-10-31 12:58:44 +0000202 // in the way when we move
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100203 // source.
204 PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100205 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100206 &error_msg);
207 ASSERT_TRUE(dest.IsValid());
208 MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100209 3 * kPageSize,
210 PROT_WRITE | PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100211 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100212 &error_msg);
213 ASSERT_TRUE(source.IsValid());
214 uint8_t* source_addr = source.Begin();
215 uint8_t* dest_addr = dest.Begin();
Alex Lightca97ada2018-02-02 09:25:31 -0800216 ASSERT_TRUE(IsAddressMapped(source_addr));
217
218 // Fill the source with random data.
219 std::vector<uint8_t> data = RandomData(3 * kPageSize);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100220 memcpy(source.Begin(), data.data(), data.size());
Alex Lightca97ada2018-02-02 09:25:31 -0800221
222 // Make the dest smaller so that we know we'll have space.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100223 dest.SetSize(kPageSize);
Alex Lightca97ada2018-02-02 09:25:31 -0800224
225 ASSERT_TRUE(IsAddressMapped(dest_addr));
226 ASSERT_FALSE(IsAddressMapped(dest_addr + 2 * kPageSize));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100227 ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
Alex Lightca97ada2018-02-02 09:25:31 -0800228
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100229 ASSERT_TRUE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
Alex Lightca97ada2018-02-02 09:25:31 -0800230
231 ASSERT_FALSE(IsAddressMapped(source_addr));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100232 ASSERT_EQ(dest.Size(), static_cast<size_t>(3 * kPageSize));
Alex Lightca97ada2018-02-02 09:25:31 -0800233 ASSERT_TRUE(IsAddressMapped(dest_addr));
234 ASSERT_TRUE(IsAddressMapped(dest_addr + 2 * kPageSize));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100235 ASSERT_FALSE(source.IsValid());
Alex Lightca97ada2018-02-02 09:25:31 -0800236
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100237 ASSERT_EQ(memcmp(dest.Begin(), data.data(), dest.Size()), 0);
Alex Lightca97ada2018-02-02 09:25:31 -0800238}
239
240TEST_F(MemMapTest, ReplaceMapping_MakeSmaller) {
241 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100242 MemMap dest = MemMap::MapAnonymous("MapAnonymousEmpty-atomic-replace-dest",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100243 3 * kPageSize,
244 PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100245 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100246 &error_msg);
247 ASSERT_TRUE(dest.IsValid());
248 MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100249 kPageSize,
250 PROT_WRITE | PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100251 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100252 &error_msg);
253 ASSERT_TRUE(source.IsValid());
254 uint8_t* source_addr = source.Begin();
255 uint8_t* dest_addr = dest.Begin();
Alex Lightca97ada2018-02-02 09:25:31 -0800256 ASSERT_TRUE(IsAddressMapped(source_addr));
257 ASSERT_TRUE(IsAddressMapped(dest_addr));
258 ASSERT_TRUE(IsAddressMapped(dest_addr + 2 * kPageSize));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100259 ASSERT_EQ(dest.Size(), static_cast<size_t>(3 * kPageSize));
Alex Lightca97ada2018-02-02 09:25:31 -0800260
261 std::vector<uint8_t> data = RandomData(kPageSize);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100262 memcpy(source.Begin(), data.data(), kPageSize);
Alex Lightca97ada2018-02-02 09:25:31 -0800263
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100264 ASSERT_TRUE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
Alex Lightca97ada2018-02-02 09:25:31 -0800265
266 ASSERT_FALSE(IsAddressMapped(source_addr));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100267 ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
Alex Lightca97ada2018-02-02 09:25:31 -0800268 ASSERT_TRUE(IsAddressMapped(dest_addr));
269 ASSERT_FALSE(IsAddressMapped(dest_addr + 2 * kPageSize));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100270 ASSERT_FALSE(source.IsValid());
Alex Lightca97ada2018-02-02 09:25:31 -0800271
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100272 ASSERT_EQ(memcmp(dest.Begin(), data.data(), dest.Size()), 0);
Alex Lightca97ada2018-02-02 09:25:31 -0800273}
274
275TEST_F(MemMapTest, ReplaceMapping_FailureOverlap) {
276 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100277 MemMap dest =
Alex Lightca97ada2018-02-02 09:25:31 -0800278 MemMap::MapAnonymous(
279 "MapAnonymousEmpty-atomic-replace-dest",
Alex Lightca97ada2018-02-02 09:25:31 -0800280 3 * kPageSize, // Need to make it larger initially so we know there won't be mappings in
Vladimir Marko830f3562018-10-31 12:58:44 +0000281 // the way when we move source.
Alex Lightca97ada2018-02-02 09:25:31 -0800282 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100283 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100284 &error_msg);
285 ASSERT_TRUE(dest.IsValid());
Alex Lightca97ada2018-02-02 09:25:31 -0800286 // Resize down to 1 page so we can remap the rest.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100287 dest.SetSize(kPageSize);
Alex Lightca97ada2018-02-02 09:25:31 -0800288 // Create source from the last 2 pages
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100289 MemMap source = MemMap::MapAnonymous("MapAnonymous-atomic-replace-source",
290 dest.Begin() + kPageSize,
291 2 * kPageSize,
292 PROT_WRITE | PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100293 /*low_4gb=*/ false,
294 /*reuse=*/ false,
295 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100296 &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();
Alex Lightca97ada2018-02-02 09:25:31 -0800301 ASSERT_TRUE(IsAddressMapped(source_addr));
302
303 // Fill the source and dest with random data.
304 std::vector<uint8_t> data = RandomData(2 * kPageSize);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100305 memcpy(source.Begin(), data.data(), data.size());
Alex Lightca97ada2018-02-02 09:25:31 -0800306 std::vector<uint8_t> dest_data = RandomData(kPageSize);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100307 memcpy(dest.Begin(), dest_data.data(), dest_data.size());
Alex Lightca97ada2018-02-02 09:25:31 -0800308
309 ASSERT_TRUE(IsAddressMapped(dest_addr));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100310 ASSERT_EQ(dest.Size(), static_cast<size_t>(kPageSize));
Alex Lightca97ada2018-02-02 09:25:31 -0800311
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100312 ASSERT_FALSE(dest.ReplaceWith(&source, &error_msg)) << error_msg;
Alex Lightca97ada2018-02-02 09:25:31 -0800313
Alex Lightca97ada2018-02-02 09:25:31 -0800314 ASSERT_TRUE(IsAddressMapped(source_addr));
315 ASSERT_TRUE(IsAddressMapped(dest_addr));
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100316 ASSERT_EQ(source.Size(), data.size());
317 ASSERT_EQ(dest.Size(), dest_data.size());
Alex Lightca97ada2018-02-02 09:25:31 -0800318
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100319 ASSERT_EQ(memcmp(source.Begin(), data.data(), data.size()), 0);
320 ASSERT_EQ(memcmp(dest.Begin(), dest_data.data(), dest_data.size()), 0);
Alex Lightca97ada2018-02-02 09:25:31 -0800321}
322#endif // HAVE_MREMAP_SYSCALL
323
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700324TEST_F(MemMapTest, MapAnonymousEmpty) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700325 CommonInit();
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700326 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100327 MemMap map = MemMap::MapAnonymous("MapAnonymousEmpty",
Vladimir Marko11306592018-10-26 14:22:59 +0100328 /*byte_count=*/ 0,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100329 PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100330 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100331 &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",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100337 kPageSize,
338 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100339 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100340 &error_msg);
341 ASSERT_TRUE(map.IsValid()) << error_msg;
Ian Rogers8d31bbd2013-10-13 10:44:14 -0700342 ASSERT_TRUE(error_msg.empty());
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700343}
344
Mathieu Chartier486932a2016-02-24 10:09:23 -0800345TEST_F(MemMapTest, MapAnonymousFailNullError) {
346 CommonInit();
347 // Test that we don't crash with a null error_str when mapping at an invalid location.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100348 MemMap map = MemMap::MapAnonymous("MapAnonymousInvalid",
349 reinterpret_cast<uint8_t*>(kPageSize),
350 0x20000,
351 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100352 /*low_4gb=*/ false,
353 /*reuse=*/ false,
354 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100355 nullptr);
356 ASSERT_FALSE(map.IsValid());
Mathieu Chartier486932a2016-02-24 10:09:23 -0800357}
358
Ian Rogersef7d42f2014-01-06 12:55:46 -0800359#ifdef __LP64__
360TEST_F(MemMapTest, MapAnonymousEmpty32bit) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700361 CommonInit();
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700362 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100363 MemMap map = MemMap::MapAnonymous("MapAnonymousEmpty",
Vladimir Marko11306592018-10-26 14:22:59 +0100364 /*byte_count=*/ 0,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100365 PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100366 /*low_4gb=*/ true,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100367 &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",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100373 kPageSize,
374 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100375 /*low_4gb=*/ true,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100376 &error_msg);
377 ASSERT_TRUE(map.IsValid()) << error_msg;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800378 ASSERT_TRUE(error_msg.empty());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100379 ASSERT_LT(reinterpret_cast<uintptr_t>(map.BaseBegin()), 1ULL << 32);
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700380}
Mathieu Chartier42bddce2015-11-09 15:16:56 -0800381TEST_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));
Andreas Gampe0de385f2018-10-11 11:11:13 -0700388 MemMap map = MemMap::MapFile(/*byte_count=*/kMapSize,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100389 PROT_READ,
390 MAP_PRIVATE,
391 scratch_file.GetFd(),
Andreas Gampe0de385f2018-10-11 11:11:13 -0700392 /*start=*/0,
393 /*low_4gb=*/true,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100394 scratch_file.GetFilename().c_str(),
395 &error_msg);
396 ASSERT_TRUE(map.IsValid()) << error_msg;
Mathieu Chartier42bddce2015-11-09 15:16:56 -0800397 ASSERT_TRUE(error_msg.empty());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100398 ASSERT_EQ(map.Size(), kMapSize);
399 ASSERT_LT(reinterpret_cast<uintptr_t>(map.BaseBegin()), 1ULL << 32);
Mathieu Chartier42bddce2015-11-09 15:16:56 -0800400}
Ian Rogersef7d42f2014-01-06 12:55:46 -0800401#endif
402
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700403TEST_F(MemMapTest, MapAnonymousExactAddr) {
Vladimir Marko1c1442a2018-10-26 13:39:14 +0100404 // 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
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700410 CommonInit();
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700411 std::string error_msg;
Mathieu Chartier16d29f82015-11-10 10:32:52 -0800412 // Find a valid address.
Andreas Gampe0de385f2018-10-11 11:11:13 -0700413 uint8_t* valid_address = GetValidMapAddress(kPageSize, /*low_4gb=*/false);
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700414 // Map at an address that should work, which should succeed.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100415 MemMap map0 = MemMap::MapAnonymous("MapAnonymous0",
416 valid_address,
417 kPageSize,
418 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100419 /*low_4gb=*/ false,
420 /*reuse=*/ false,
421 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100422 &error_msg);
423 ASSERT_TRUE(map0.IsValid()) << error_msg;
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700424 ASSERT_TRUE(error_msg.empty());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100425 ASSERT_TRUE(map0.BaseBegin() == valid_address);
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700426 // Map at an unspecified address, which should succeed.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100427 MemMap map1 = MemMap::MapAnonymous("MapAnonymous1",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100428 kPageSize,
429 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100430 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100431 &error_msg);
432 ASSERT_TRUE(map1.IsValid()) << error_msg;
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700433 ASSERT_TRUE(error_msg.empty());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100434 ASSERT_TRUE(map1.BaseBegin() != nullptr);
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700435 // Attempt to map at the same address, which should fail.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100436 MemMap map2 = MemMap::MapAnonymous("MapAnonymous2",
437 reinterpret_cast<uint8_t*>(map1.BaseBegin()),
438 kPageSize,
439 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100440 /*low_4gb=*/ false,
441 /*reuse=*/ false,
442 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100443 &error_msg);
444 ASSERT_FALSE(map2.IsValid()) << error_msg;
Hiroshi Yamauchi4fb5df82014-03-13 15:10:27 -0700445 ASSERT_TRUE(!error_msg.empty());
446}
447
Ian Rogersef7d42f2014-01-06 12:55:46 -0800448TEST_F(MemMapTest, RemapAtEnd) {
449 RemapAtEndTest(false);
450}
451
452#ifdef __LP64__
453TEST_F(MemMapTest, RemapAtEnd32bit) {
454 RemapAtEndTest(true);
455}
456#endif
Hiroshi Yamauchifd7e7f12013-10-22 14:17:48 -0700457
Orion Hodson1d3fd082018-09-28 09:38:35 +0100458TEST_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
Andreas Gampe0de385f2018-10-11 11:11:13 -0700472 MemMap map = MemMap::MapFile(/*byte_count=*/kMapSize,
Orion Hodson1d3fd082018-09-28 09:38:35 +0100473 PROT_READ,
474 MAP_PRIVATE,
475 scratch_file.GetFd(),
Andreas Gampe0de385f2018-10-11 11:11:13 -0700476 /*start=*/0,
477 /*low_4gb=*/true,
Orion Hodson1d3fd082018-09-28 09:38:35 +0100478 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
Qiming Shi84d49cc2014-04-24 15:38:41 +0800505TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
Roland Levillain14306b82016-01-20 12:13:57 +0000506 // Some MIPS32 hardware (namely the Creator Ci20 development board)
507 // cannot allocate in the 2GB-4GB region.
508 TEST_DISABLED_FOR_MIPS();
509
Roland Levillain0b0d3b42018-06-14 13:55:49 +0100510 // This test does not work under AddressSanitizer.
511 // Historical note: This test did not work under Valgrind either.
Roland Levillain05e34f42018-05-24 13:19:05 +0000512 TEST_DISABLED_FOR_MEMORY_TOOL();
513
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700514 CommonInit();
Roland Levillain05e34f42018-05-24 13:19:05 +0000515 constexpr size_t size = 0x100000;
516 // Try all addresses starting from 2GB to 4GB.
517 size_t start_addr = 2 * GB;
518 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100519 MemMap map;
Roland Levillain05e34f42018-05-24 13:19:05 +0000520 for (; start_addr <= std::numeric_limits<uint32_t>::max() - size; start_addr += size) {
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100521 map = MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
522 reinterpret_cast<uint8_t*>(start_addr),
523 size,
524 PROT_READ | PROT_WRITE,
Andreas Gampe0de385f2018-10-11 11:11:13 -0700525 /*low_4gb=*/ true,
Vladimir Marko11306592018-10-26 14:22:59 +0100526 /*reuse=*/ false,
527 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100528 &error_msg);
529 if (map.IsValid()) {
Roland Levillain05e34f42018-05-24 13:19:05 +0000530 break;
Mathieu Chartier16d29f82015-11-10 10:32:52 -0800531 }
Andreas Gampe928f72b2014-09-09 19:53:48 -0700532 }
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100533 ASSERT_TRUE(map.IsValid()) << error_msg;
534 ASSERT_GE(reinterpret_cast<uintptr_t>(map.End()), 2u * GB);
Roland Levillain05e34f42018-05-24 13:19:05 +0000535 ASSERT_TRUE(error_msg.empty());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100536 ASSERT_EQ(map.BaseBegin(), reinterpret_cast<void*>(start_addr));
Qiming Shi84d49cc2014-04-24 15:38:41 +0800537}
538
539TEST_F(MemMapTest, MapAnonymousOverflow) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700540 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800541 std::string error_msg;
542 uintptr_t ptr = 0;
543 ptr -= kPageSize; // Now it's close to the top.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100544 MemMap map = MemMap::MapAnonymous("MapAnonymousOverflow",
545 reinterpret_cast<uint8_t*>(ptr),
546 2 * kPageSize, // brings it over the top.
547 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100548 /*low_4gb=*/ false,
549 /*reuse=*/ false,
550 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100551 &error_msg);
552 ASSERT_FALSE(map.IsValid());
Qiming Shi84d49cc2014-04-24 15:38:41 +0800553 ASSERT_FALSE(error_msg.empty());
554}
555
556#ifdef __LP64__
557TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700558 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800559 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100560 MemMap map =
Vladimir Marko5c42c292015-02-25 12:02:49 +0000561 MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
562 reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
563 kPageSize,
564 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100565 /*low_4gb=*/ true,
566 /*reuse=*/ false,
567 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100568 &error_msg);
569 ASSERT_FALSE(map.IsValid());
Qiming Shi84d49cc2014-04-24 15:38:41 +0800570 ASSERT_FALSE(error_msg.empty());
571}
572
573TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700574 CommonInit();
Qiming Shi84d49cc2014-04-24 15:38:41 +0800575 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100576 MemMap map = MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
Vladimir Marko830f3562018-10-31 12:58:44 +0000577 /*addr=*/ reinterpret_cast<uint8_t*>(0xF0000000),
578 /*byte_count=*/ 0x20000000,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100579 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100580 /*low_4gb=*/ true,
581 /*reuse=*/ false,
582 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100583 &error_msg);
584 ASSERT_FALSE(map.IsValid());
Qiming Shi84d49cc2014-04-24 15:38:41 +0800585 ASSERT_FALSE(error_msg.empty());
586}
587#endif
588
Vladimir Marko5c42c292015-02-25 12:02:49 +0000589TEST_F(MemMapTest, MapAnonymousReuse) {
590 CommonInit();
591 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100592 MemMap map = MemMap::MapAnonymous("MapAnonymousReserve",
Vladimir Marko830f3562018-10-31 12:58:44 +0000593 /*byte_count=*/ 0x20000,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100594 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100595 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100596 &error_msg);
597 ASSERT_TRUE(map.IsValid());
Vladimir Marko5c42c292015-02-25 12:02:49 +0000598 ASSERT_TRUE(error_msg.empty());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100599 MemMap map2 = MemMap::MapAnonymous("MapAnonymousReused",
Vladimir Marko830f3562018-10-31 12:58:44 +0000600 /*addr=*/ reinterpret_cast<uint8_t*>(map.BaseBegin()),
601 /*byte_count=*/ 0x10000,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100602 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100603 /*low_4gb=*/ false,
604 /*reuse=*/ true,
605 /*reservation=*/ nullptr,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100606 &error_msg);
607 ASSERT_TRUE(map2.IsValid());
Vladimir Marko5c42c292015-02-25 12:02:49 +0000608 ASSERT_TRUE(error_msg.empty());
609}
610
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700611TEST_F(MemMapTest, CheckNoGaps) {
Mathieu Chartier6e88ef62014-10-14 15:01:24 -0700612 CommonInit();
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700613 std::string error_msg;
614 constexpr size_t kNumPages = 3;
615 // Map a 3-page mem map.
Vladimir Marko11306592018-10-26 14:22:59 +0100616 MemMap reservation = MemMap::MapAnonymous("MapAnonymous0",
617 kPageSize * kNumPages,
618 PROT_READ | PROT_WRITE,
619 /*low_4gb=*/ false,
620 &error_msg);
621 ASSERT_TRUE(reservation.IsValid()) << error_msg;
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700622 ASSERT_TRUE(error_msg.empty());
623 // Record the base address.
Vladimir Marko11306592018-10-26 14:22:59 +0100624 uint8_t* map_base = reinterpret_cast<uint8_t*>(reservation.BaseBegin());
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700625
Vladimir Marko11306592018-10-26 14:22:59 +0100626 // Map at the same address, taking from the `map` reservation.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100627 MemMap map0 = MemMap::MapAnonymous("MapAnonymous0",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100628 kPageSize,
629 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100630 /*low_4gb=*/ false,
631 &reservation,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100632 &error_msg);
633 ASSERT_TRUE(map0.IsValid()) << error_msg;
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700634 ASSERT_TRUE(error_msg.empty());
Vladimir Marko11306592018-10-26 14:22:59 +0100635 ASSERT_EQ(map_base, map0.Begin());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100636 MemMap map1 = MemMap::MapAnonymous("MapAnonymous1",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100637 kPageSize,
638 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100639 /*low_4gb=*/ false,
640 &reservation,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100641 &error_msg);
642 ASSERT_TRUE(map1.IsValid()) << error_msg;
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700643 ASSERT_TRUE(error_msg.empty());
Vladimir Marko11306592018-10-26 14:22:59 +0100644 ASSERT_EQ(map_base + kPageSize, map1.Begin());
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100645 MemMap map2 = MemMap::MapAnonymous("MapAnonymous2",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100646 kPageSize,
647 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100648 /*low_4gb=*/ false,
649 &reservation,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100650 &error_msg);
651 ASSERT_TRUE(map2.IsValid()) << error_msg;
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700652 ASSERT_TRUE(error_msg.empty());
Vladimir Marko11306592018-10-26 14:22:59 +0100653 ASSERT_EQ(map_base + 2 * kPageSize, map2.Begin());
654 ASSERT_FALSE(reservation.IsValid()); // The entire reservation was used.
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700655
656 // One-map cases.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100657 ASSERT_TRUE(MemMap::CheckNoGaps(map0, map0));
658 ASSERT_TRUE(MemMap::CheckNoGaps(map1, map1));
659 ASSERT_TRUE(MemMap::CheckNoGaps(map2, map2));
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700660
661 // Two or three-map cases.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100662 ASSERT_TRUE(MemMap::CheckNoGaps(map0, map1));
663 ASSERT_TRUE(MemMap::CheckNoGaps(map1, map2));
664 ASSERT_TRUE(MemMap::CheckNoGaps(map0, map2));
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700665
666 // Unmap the middle one.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100667 map1.Reset();
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700668
669 // Should return false now that there's a gap in the middle.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100670 ASSERT_FALSE(MemMap::CheckNoGaps(map0, map2));
Hiroshi Yamauchi3eed93d2014-06-04 11:43:59 -0700671}
672
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800673TEST_F(MemMapTest, AlignBy) {
674 CommonInit();
675 std::string error_msg;
676 // Cast the page size to size_t.
677 const size_t page_size = static_cast<size_t>(kPageSize);
678 // Map a region.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100679 MemMap m0 = MemMap::MapAnonymous("MemMapTest_AlignByTest_map0",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100680 14 * page_size,
681 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100682 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100683 &error_msg);
684 ASSERT_TRUE(m0.IsValid());
685 uint8_t* base0 = m0.Begin();
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800686 ASSERT_TRUE(base0 != nullptr) << error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100687 ASSERT_EQ(m0.Size(), 14 * page_size);
688 ASSERT_EQ(m0.BaseBegin(), base0);
689 ASSERT_EQ(m0.BaseSize(), m0.Size());
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800690
691 // Break it into several regions by using RemapAtEnd.
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100692 MemMap m1 = m0.RemapAtEnd(base0 + 3 * page_size,
693 "MemMapTest_AlignByTest_map1",
694 PROT_READ | PROT_WRITE,
695 &error_msg);
696 uint8_t* base1 = m1.Begin();
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800697 ASSERT_TRUE(base1 != nullptr) << error_msg;
698 ASSERT_EQ(base1, base0 + 3 * page_size);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100699 ASSERT_EQ(m0.Size(), 3 * page_size);
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800700
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100701 MemMap m2 = m1.RemapAtEnd(base1 + 4 * page_size,
702 "MemMapTest_AlignByTest_map2",
703 PROT_READ | PROT_WRITE,
704 &error_msg);
705 uint8_t* base2 = m2.Begin();
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800706 ASSERT_TRUE(base2 != nullptr) << error_msg;
707 ASSERT_EQ(base2, base1 + 4 * page_size);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100708 ASSERT_EQ(m1.Size(), 4 * page_size);
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800709
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100710 MemMap m3 = m2.RemapAtEnd(base2 + 3 * page_size,
711 "MemMapTest_AlignByTest_map1",
712 PROT_READ | PROT_WRITE,
713 &error_msg);
714 uint8_t* base3 = m3.Begin();
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800715 ASSERT_TRUE(base3 != nullptr) << error_msg;
716 ASSERT_EQ(base3, base2 + 3 * page_size);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100717 ASSERT_EQ(m2.Size(), 3 * page_size);
718 ASSERT_EQ(m3.Size(), 4 * page_size);
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800719
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100720 uint8_t* end0 = base0 + m0.Size();
721 uint8_t* end1 = base1 + m1.Size();
722 uint8_t* end2 = base2 + m2.Size();
723 uint8_t* end3 = base3 + m3.Size();
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800724
725 ASSERT_EQ(static_cast<size_t>(end3 - base0), 14 * page_size);
726
727 if (IsAlignedParam(base0, 2 * page_size)) {
728 ASSERT_FALSE(IsAlignedParam(base1, 2 * page_size));
729 ASSERT_FALSE(IsAlignedParam(base2, 2 * page_size));
730 ASSERT_TRUE(IsAlignedParam(base3, 2 * page_size));
731 ASSERT_TRUE(IsAlignedParam(end3, 2 * page_size));
732 } else {
733 ASSERT_TRUE(IsAlignedParam(base1, 2 * page_size));
734 ASSERT_TRUE(IsAlignedParam(base2, 2 * page_size));
735 ASSERT_FALSE(IsAlignedParam(base3, 2 * page_size));
736 ASSERT_FALSE(IsAlignedParam(end3, 2 * page_size));
737 }
738
739 // Align by 2 * page_size;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100740 m0.AlignBy(2 * page_size);
741 m1.AlignBy(2 * page_size);
742 m2.AlignBy(2 * page_size);
743 m3.AlignBy(2 * page_size);
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800744
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100745 EXPECT_TRUE(IsAlignedParam(m0.Begin(), 2 * page_size));
746 EXPECT_TRUE(IsAlignedParam(m1.Begin(), 2 * page_size));
747 EXPECT_TRUE(IsAlignedParam(m2.Begin(), 2 * page_size));
748 EXPECT_TRUE(IsAlignedParam(m3.Begin(), 2 * page_size));
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800749
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100750 EXPECT_TRUE(IsAlignedParam(m0.Begin() + m0.Size(), 2 * page_size));
751 EXPECT_TRUE(IsAlignedParam(m1.Begin() + m1.Size(), 2 * page_size));
752 EXPECT_TRUE(IsAlignedParam(m2.Begin() + m2.Size(), 2 * page_size));
753 EXPECT_TRUE(IsAlignedParam(m3.Begin() + m3.Size(), 2 * page_size));
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800754
755 if (IsAlignedParam(base0, 2 * page_size)) {
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100756 EXPECT_EQ(m0.Begin(), base0);
757 EXPECT_EQ(m0.Begin() + m0.Size(), end0 - page_size);
758 EXPECT_EQ(m1.Begin(), base1 + page_size);
759 EXPECT_EQ(m1.Begin() + m1.Size(), end1 - page_size);
760 EXPECT_EQ(m2.Begin(), base2 + page_size);
761 EXPECT_EQ(m2.Begin() + m2.Size(), end2);
762 EXPECT_EQ(m3.Begin(), base3);
763 EXPECT_EQ(m3.Begin() + m3.Size(), end3);
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800764 } else {
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100765 EXPECT_EQ(m0.Begin(), base0 + page_size);
766 EXPECT_EQ(m0.Begin() + m0.Size(), end0);
767 EXPECT_EQ(m1.Begin(), base1);
768 EXPECT_EQ(m1.Begin() + m1.Size(), end1);
769 EXPECT_EQ(m2.Begin(), base2);
770 EXPECT_EQ(m2.Begin() + m2.Size(), end2 - page_size);
771 EXPECT_EQ(m3.Begin(), base3 + page_size);
772 EXPECT_EQ(m3.Begin() + m3.Size(), end3 - page_size);
Hiroshi Yamauchi3c3c4a12017-02-21 16:49:59 -0800773 }
774}
775
Vladimir Markoc09cd052018-08-23 16:36:36 +0100776TEST_F(MemMapTest, Reservation) {
777 CommonInit();
778 std::string error_msg;
779 ScratchFile scratch_file;
780 constexpr size_t kMapSize = 5 * kPageSize;
781 std::unique_ptr<uint8_t[]> data(new uint8_t[kMapSize]());
782 ASSERT_TRUE(scratch_file.GetFile()->WriteFully(&data[0], kMapSize));
783
784 MemMap reservation = MemMap::MapAnonymous("Test reservation",
Vladimir Markoc09cd052018-08-23 16:36:36 +0100785 kMapSize,
786 PROT_NONE,
Vladimir Marko11306592018-10-26 14:22:59 +0100787 /*low_4gb=*/ false,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100788 &error_msg);
789 ASSERT_TRUE(reservation.IsValid());
790 ASSERT_TRUE(error_msg.empty());
791
792 // Map first part of the reservation.
793 constexpr size_t kChunk1Size = kPageSize - 1u;
794 static_assert(kChunk1Size < kMapSize, "We want to split the reservation.");
795 uint8_t* addr1 = reservation.Begin();
796 MemMap map1 = MemMap::MapFileAtAddress(addr1,
Vladimir Marko11306592018-10-26 14:22:59 +0100797 /*byte_count=*/ kChunk1Size,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100798 PROT_READ,
799 MAP_PRIVATE,
800 scratch_file.GetFd(),
Vladimir Marko11306592018-10-26 14:22:59 +0100801 /*start=*/ 0,
802 /*low_4gb=*/ false,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100803 scratch_file.GetFilename().c_str(),
Vladimir Marko11306592018-10-26 14:22:59 +0100804 /*reuse=*/ false,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100805 &reservation,
806 &error_msg);
807 ASSERT_TRUE(map1.IsValid()) << error_msg;
808 ASSERT_TRUE(error_msg.empty());
809 ASSERT_EQ(map1.Size(), kChunk1Size);
810 ASSERT_EQ(addr1, map1.Begin());
811 ASSERT_TRUE(reservation.IsValid());
812 // Entire pages are taken from the `reservation`.
813 ASSERT_LT(map1.End(), map1.BaseEnd());
814 ASSERT_EQ(map1.BaseEnd(), reservation.Begin());
815
816 // Map second part as an anonymous mapping.
817 constexpr size_t kChunk2Size = 2 * kPageSize;
818 DCHECK_LT(kChunk2Size, reservation.Size()); // We want to split the reservation.
819 uint8_t* addr2 = reservation.Begin();
820 MemMap map2 = MemMap::MapAnonymous("MiddleReservation",
821 addr2,
Vladimir Marko11306592018-10-26 14:22:59 +0100822 /*byte_count=*/ kChunk2Size,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100823 PROT_READ,
Vladimir Marko11306592018-10-26 14:22:59 +0100824 /*low_4gb=*/ false,
825 /*reuse=*/ false,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100826 &reservation,
827 &error_msg);
828 ASSERT_TRUE(map2.IsValid()) << error_msg;
829 ASSERT_TRUE(error_msg.empty());
830 ASSERT_EQ(map2.Size(), kChunk2Size);
831 ASSERT_EQ(addr2, map2.Begin());
832 ASSERT_EQ(map2.End(), map2.BaseEnd()); // kChunk2Size is page aligned.
833 ASSERT_EQ(map2.BaseEnd(), reservation.Begin());
834
835 // Map the rest of the reservation except the last byte.
836 const size_t kChunk3Size = reservation.Size() - 1u;
837 uint8_t* addr3 = reservation.Begin();
838 MemMap map3 = MemMap::MapFileAtAddress(addr3,
Vladimir Marko11306592018-10-26 14:22:59 +0100839 /*byte_count=*/ kChunk3Size,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100840 PROT_READ,
841 MAP_PRIVATE,
842 scratch_file.GetFd(),
Vladimir Marko11306592018-10-26 14:22:59 +0100843 /*start=*/ dchecked_integral_cast<size_t>(addr3 - addr1),
844 /*low_4gb=*/ false,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100845 scratch_file.GetFilename().c_str(),
Vladimir Marko11306592018-10-26 14:22:59 +0100846 /*reuse=*/ false,
Vladimir Markoc09cd052018-08-23 16:36:36 +0100847 &reservation,
848 &error_msg);
849 ASSERT_TRUE(map3.IsValid()) << error_msg;
850 ASSERT_TRUE(error_msg.empty());
851 ASSERT_EQ(map3.Size(), kChunk3Size);
852 ASSERT_EQ(addr3, map3.Begin());
853 // Entire pages are taken from the `reservation`, so it's now exhausted.
854 ASSERT_FALSE(reservation.IsValid());
855
856 // Now split the MiddleReservation.
857 constexpr size_t kChunk2ASize = kPageSize - 1u;
858 DCHECK_LT(kChunk2ASize, map2.Size()); // We want to split the reservation.
859 MemMap map2a = map2.TakeReservedMemory(kChunk2ASize);
860 ASSERT_TRUE(map2a.IsValid()) << error_msg;
861 ASSERT_TRUE(error_msg.empty());
862 ASSERT_EQ(map2a.Size(), kChunk2ASize);
863 ASSERT_EQ(addr2, map2a.Begin());
864 ASSERT_TRUE(map2.IsValid());
865 ASSERT_LT(map2a.End(), map2a.BaseEnd());
866 ASSERT_EQ(map2a.BaseEnd(), map2.Begin());
867
868 // And take the rest of the middle reservation.
869 const size_t kChunk2BSize = map2.Size() - 1u;
870 uint8_t* addr2b = map2.Begin();
871 MemMap map2b = map2.TakeReservedMemory(kChunk2BSize);
872 ASSERT_TRUE(map2b.IsValid()) << error_msg;
873 ASSERT_TRUE(error_msg.empty());
874 ASSERT_EQ(map2b.Size(), kChunk2ASize);
875 ASSERT_EQ(addr2b, map2b.Begin());
876 ASSERT_FALSE(map2.IsValid());
877}
878
Brian Carlstrom9004cb62013-07-26 15:48:31 -0700879} // namespace art
Andreas Gampec857f4a2018-10-25 13:12:37 -0700880
881namespace {
882
883class DumpMapsOnFailListener : public testing::EmptyTestEventListener {
884 void OnTestPartResult(const testing::TestPartResult& result) override {
885 switch (result.type()) {
886 case testing::TestPartResult::kFatalFailure:
887 art::PrintFileToLog("/proc/self/maps", android::base::LogSeverity::ERROR);
888 break;
889
890 // TODO: Could consider logging on EXPECT failures.
891 case testing::TestPartResult::kNonFatalFailure:
Elliott Hughese00648f2018-10-30 08:34:52 -0700892 case testing::TestPartResult::kSkip:
Andreas Gampec857f4a2018-10-25 13:12:37 -0700893 case testing::TestPartResult::kSuccess:
894 break;
895 }
896 }
897};
898
899} // namespace
900
901// Inject our listener into the test runner.
902extern "C"
903__attribute__((visibility("default"))) __attribute__((used))
904void ArtTestGlobalInit() {
Andreas Gampec857f4a2018-10-25 13:12:37 -0700905 testing::UnitTest::GetInstance()->listeners().Append(new DumpMapsOnFailListener());
906}