github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/mremap.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <errno.h> 16 #include <string.h> 17 #include <sys/mman.h> 18 19 #include <string> 20 21 #include "gmock/gmock.h" 22 #include "absl/strings/string_view.h" 23 #include "test/util/file_descriptor.h" 24 #include "test/util/logging.h" 25 #include "test/util/memory_util.h" 26 #include "test/util/multiprocess_util.h" 27 #include "test/util/posix_error.h" 28 #include "test/util/temp_path.h" 29 #include "test/util/test_util.h" 30 31 using ::testing::_; 32 33 namespace gvisor { 34 namespace testing { 35 36 namespace { 37 38 // Fixture for mremap tests parameterized by mmap flags. 39 using MremapParamTest = ::testing::TestWithParam<int>; 40 41 TEST_P(MremapParamTest, Noop) { 42 Mapping const m = 43 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 44 45 ASSERT_THAT(Mremap(m.ptr(), kPageSize, kPageSize, 0, nullptr), 46 IsPosixErrorOkAndHolds(m.ptr())); 47 EXPECT_TRUE(IsMapped(m.addr())); 48 } 49 50 TEST_P(MremapParamTest, InPlace_ShrinkingWholeVMA) { 51 Mapping const m = 52 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 53 54 const auto rest = [&] { 55 // N.B. we must be in a single-threaded subprocess to ensure a 56 // background thread doesn't concurrently map the second page. 57 void* addr = mremap(m.ptr(), 2 * kPageSize, kPageSize, 0, nullptr); 58 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 59 TEST_CHECK(addr == m.ptr()); 60 MaybeSave(); 61 62 TEST_CHECK(IsMapped(m.addr())); 63 TEST_CHECK(!IsMapped(m.addr() + kPageSize)); 64 }; 65 66 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 67 } 68 69 TEST_P(MremapParamTest, InPlace_ShrinkingPartialVMA) { 70 Mapping const m = 71 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam())); 72 73 const auto rest = [&] { 74 void* addr = mremap(m.ptr(), 2 * kPageSize, kPageSize, 0, nullptr); 75 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 76 TEST_CHECK(addr == m.ptr()); 77 MaybeSave(); 78 79 TEST_CHECK(IsMapped(m.addr())); 80 TEST_CHECK(!IsMapped(m.addr() + kPageSize)); 81 TEST_CHECK(IsMapped(m.addr() + 2 * kPageSize)); 82 }; 83 84 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 85 } 86 87 TEST_P(MremapParamTest, InPlace_ShrinkingAcrossVMAs) { 88 Mapping const m = 89 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_READ, GetParam())); 90 // Changing permissions on the first page forces it to become a separate vma. 91 ASSERT_THAT(mprotect(m.ptr(), kPageSize, PROT_NONE), SyscallSucceeds()); 92 93 const auto rest = [&] { 94 // Both old_size and new_size now span two vmas; mremap 95 // shouldn't care. 96 void* addr = mremap(m.ptr(), 3 * kPageSize, 2 * kPageSize, 0, nullptr); 97 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 98 TEST_CHECK(addr == m.ptr()); 99 MaybeSave(); 100 101 TEST_CHECK(IsMapped(m.addr())); 102 TEST_CHECK(IsMapped(m.addr() + kPageSize)); 103 TEST_CHECK(!IsMapped(m.addr() + 2 * kPageSize)); 104 }; 105 106 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 107 } 108 109 TEST_P(MremapParamTest, InPlace_ExpansionSuccess) { 110 Mapping const m = 111 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 112 113 const auto rest = [&] { 114 // Unmap the second page so that the first can be expanded back into it. 115 // 116 // N.B. we must be in a single-threaded subprocess to ensure a 117 // background thread doesn't concurrently map this page. 118 TEST_PCHECK( 119 munmap(reinterpret_cast<void*>(m.addr() + kPageSize), kPageSize) == 0); 120 MaybeSave(); 121 122 void* addr = mremap(m.ptr(), kPageSize, 2 * kPageSize, 0, nullptr); 123 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 124 TEST_CHECK(addr == m.ptr()); 125 MaybeSave(); 126 127 TEST_CHECK(IsMapped(m.addr())); 128 TEST_CHECK(IsMapped(m.addr() + kPageSize)); 129 }; 130 131 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 132 } 133 134 TEST_P(MremapParamTest, InPlace_ExpansionFailure) { 135 Mapping const m = 136 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam())); 137 138 const auto rest = [&] { 139 // Unmap the second page, leaving a one-page hole. Trying to expand the 140 // first page to three pages should fail since the original third page 141 // is still mapped. 142 TEST_PCHECK( 143 munmap(reinterpret_cast<void*>(m.addr() + kPageSize), kPageSize) == 0); 144 MaybeSave(); 145 146 void* addr = mremap(m.ptr(), kPageSize, 3 * kPageSize, 0, nullptr); 147 TEST_CHECK_MSG(addr == MAP_FAILED, "mremap unexpectedly succeeded"); 148 TEST_PCHECK_MSG(errno == ENOMEM, "mremap failed with wrong errno"); 149 MaybeSave(); 150 151 TEST_CHECK(IsMapped(m.addr())); 152 TEST_CHECK(!IsMapped(m.addr() + kPageSize)); 153 TEST_CHECK(IsMapped(m.addr() + 2 * kPageSize)); 154 }; 155 156 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 157 } 158 159 TEST_P(MremapParamTest, MayMove_Expansion) { 160 Mapping const m = 161 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam())); 162 163 const auto rest = [&] { 164 // Unmap the second page, leaving a one-page hole. Trying to expand the 165 // first page to three pages with MREMAP_MAYMOVE should force the 166 // mapping to be relocated since the original third page is still 167 // mapped. 168 TEST_PCHECK( 169 munmap(reinterpret_cast<void*>(m.addr() + kPageSize), kPageSize) == 0); 170 MaybeSave(); 171 172 void* addr2 = 173 mremap(m.ptr(), kPageSize, 3 * kPageSize, MREMAP_MAYMOVE, nullptr); 174 TEST_PCHECK_MSG(addr2 != MAP_FAILED, "mremap failed"); 175 MaybeSave(); 176 177 const Mapping m2 = Mapping(addr2, 3 * kPageSize); 178 TEST_CHECK(m.addr() != m2.addr()); 179 180 TEST_CHECK(!IsMapped(m.addr())); 181 TEST_CHECK(!IsMapped(m.addr() + kPageSize)); 182 TEST_CHECK(IsMapped(m.addr() + 2 * kPageSize)); 183 TEST_CHECK(IsMapped(m2.addr())); 184 TEST_CHECK(IsMapped(m2.addr() + kPageSize)); 185 TEST_CHECK(IsMapped(m2.addr() + 2 * kPageSize)); 186 }; 187 188 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 189 } 190 191 TEST_P(MremapParamTest, Fixed_SourceAndDestinationCannotOverlap) { 192 Mapping const m = 193 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 194 195 ASSERT_THAT(Mremap(m.ptr(), kPageSize, kPageSize, 196 MREMAP_MAYMOVE | MREMAP_FIXED, m.ptr()), 197 PosixErrorIs(EINVAL, _)); 198 EXPECT_TRUE(IsMapped(m.addr())); 199 } 200 201 TEST_P(MremapParamTest, Fixed_SameSize) { 202 Mapping const src = 203 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 204 Mapping const dst = 205 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 206 207 const auto rest = [&] { 208 // Unmap dst to create a hole. 209 TEST_PCHECK(munmap(dst.ptr(), kPageSize) == 0); 210 MaybeSave(); 211 212 void* addr = mremap(src.ptr(), kPageSize, kPageSize, 213 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()); 214 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 215 TEST_CHECK(addr == dst.ptr()); 216 MaybeSave(); 217 218 TEST_CHECK(!IsMapped(src.addr())); 219 TEST_CHECK(IsMapped(dst.addr())); 220 }; 221 222 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 223 } 224 225 TEST_P(MremapParamTest, Fixed_SameSize_Unmapping) { 226 // Like the Fixed_SameSize case, but expect mremap to unmap the destination 227 // automatically. 228 Mapping const src = 229 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 230 Mapping const dst = 231 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 232 233 const auto rest = [&] { 234 void* addr = mremap(src.ptr(), kPageSize, kPageSize, 235 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()); 236 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 237 TEST_CHECK(addr == dst.ptr()); 238 MaybeSave(); 239 240 TEST_CHECK(!IsMapped(src.addr())); 241 TEST_CHECK(IsMapped(dst.addr())); 242 }; 243 244 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 245 } 246 247 TEST_P(MremapParamTest, Fixed_ShrinkingWholeVMA) { 248 Mapping const src = 249 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 250 Mapping const dst = 251 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 252 253 const auto rest = [&] { 254 // Unmap dst so we can check that mremap does not keep the 255 // second page. 256 TEST_PCHECK(munmap(dst.ptr(), 2 * kPageSize) == 0); 257 MaybeSave(); 258 259 void* addr = mremap(src.ptr(), 2 * kPageSize, kPageSize, 260 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()); 261 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 262 TEST_CHECK(addr == dst.ptr()); 263 MaybeSave(); 264 265 TEST_CHECK(!IsMapped(src.addr())); 266 TEST_CHECK(!IsMapped(src.addr() + kPageSize)); 267 TEST_CHECK(IsMapped(dst.addr())); 268 TEST_CHECK(!IsMapped(dst.addr() + kPageSize)); 269 }; 270 271 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 272 } 273 274 TEST_P(MremapParamTest, Fixed_ShrinkingPartialVMA) { 275 Mapping const src = 276 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_NONE, GetParam())); 277 Mapping const dst = 278 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 279 280 const auto rest = [&] { 281 // Unmap dst so we can check that mremap does not keep the 282 // second page. 283 TEST_PCHECK(munmap(dst.ptr(), 2 * kPageSize) == 0); 284 MaybeSave(); 285 286 void* addr = mremap(src.ptr(), 2 * kPageSize, kPageSize, 287 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()); 288 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 289 TEST_CHECK(addr == dst.ptr()); 290 MaybeSave(); 291 292 TEST_CHECK(!IsMapped(src.addr())); 293 TEST_CHECK(!IsMapped(src.addr() + kPageSize)); 294 TEST_CHECK(IsMapped(src.addr() + 2 * kPageSize)); 295 TEST_CHECK(IsMapped(dst.addr())); 296 TEST_CHECK(!IsMapped(dst.addr() + kPageSize)); 297 }; 298 299 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 300 } 301 302 TEST_P(MremapParamTest, Fixed_ShrinkingAcrossVMAs) { 303 Mapping const src = 304 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(3 * kPageSize, PROT_READ, GetParam())); 305 // Changing permissions on the first page forces it to become a separate vma. 306 ASSERT_THAT(mprotect(src.ptr(), kPageSize, PROT_NONE), SyscallSucceeds()); 307 Mapping const dst = 308 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 309 310 const auto rest = [&] { 311 // Unlike flags=0, MREMAP_FIXED requires that [old_address, 312 // old_address+new_size) only spans a single vma. 313 void* addr = mremap(src.ptr(), 3 * kPageSize, 2 * kPageSize, 314 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()); 315 TEST_CHECK_MSG(addr == MAP_FAILED, "mremap unexpectedly succeeded"); 316 TEST_PCHECK_MSG(errno == EFAULT, "mremap failed with wrong errno"); 317 MaybeSave(); 318 319 TEST_CHECK(IsMapped(src.addr())); 320 TEST_CHECK(IsMapped(src.addr() + kPageSize)); 321 // Despite failing, mremap should have unmapped [old_address+new_size, 322 // old_address+old_size) (i.e. the third page). 323 TEST_CHECK(!IsMapped(src.addr() + 2 * kPageSize)); 324 // Despite failing, mremap should have unmapped the destination pages. 325 TEST_CHECK(!IsMapped(dst.addr())); 326 TEST_CHECK(!IsMapped(dst.addr() + kPageSize)); 327 }; 328 329 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 330 } 331 332 TEST_P(MremapParamTest, Fixed_Expansion) { 333 Mapping const src = 334 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, GetParam())); 335 Mapping const dst = 336 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(2 * kPageSize, PROT_NONE, GetParam())); 337 338 const auto rest = [&] { 339 // Unmap dst so we can check that mremap actually maps all pages 340 // at the destination. 341 TEST_PCHECK(munmap(dst.ptr(), 2 * kPageSize) == 0); 342 MaybeSave(); 343 344 void* addr = mremap(src.ptr(), kPageSize, 2 * kPageSize, 345 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()); 346 TEST_PCHECK_MSG(addr != MAP_FAILED, "mremap failed"); 347 TEST_CHECK(addr == dst.ptr()); 348 MaybeSave(); 349 350 TEST_CHECK(!IsMapped(src.addr())); 351 TEST_CHECK(IsMapped(dst.addr())); 352 TEST_CHECK(IsMapped(dst.addr() + kPageSize)); 353 }; 354 355 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 356 } 357 358 INSTANTIATE_TEST_SUITE_P(PrivateShared, MremapParamTest, 359 ::testing::Values(MAP_PRIVATE, MAP_SHARED)); 360 361 // mremap with old_size == 0 only works with MAP_SHARED after Linux 4.14 362 // (dba58d3b8c50 "mm/mremap: fail map duplication attempts for private 363 // mappings"). 364 365 TEST(MremapTest, InPlace_Copy) { 366 Mapping const m = 367 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_SHARED)); 368 EXPECT_THAT(Mremap(m.ptr(), 0, kPageSize, 0, nullptr), 369 PosixErrorIs(ENOMEM, _)); 370 } 371 372 TEST(MremapTest, MayMove_Copy) { 373 Mapping const m = 374 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_SHARED)); 375 376 // Remainder of this test executes in a subprocess to ensure that if mremap 377 // incorrectly removes m, it is not remapped by another thread. 378 const auto rest = [&] { 379 void* ptr = mremap(m.ptr(), 0, kPageSize, MREMAP_MAYMOVE, nullptr); 380 MaybeSave(); 381 TEST_PCHECK_MSG(ptr != MAP_FAILED, "mremap failed"); 382 TEST_CHECK(ptr != m.ptr()); 383 TEST_CHECK(IsMapped(m.addr())); 384 TEST_CHECK(IsMapped(reinterpret_cast<uintptr_t>(ptr))); 385 }; 386 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 387 } 388 389 TEST(MremapTest, MustMove_Copy) { 390 Mapping const src = 391 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_SHARED)); 392 Mapping const dst = 393 ASSERT_NO_ERRNO_AND_VALUE(MmapAnon(kPageSize, PROT_NONE, MAP_PRIVATE)); 394 395 // Remainder of this test executes in a subprocess to ensure that if mremap 396 // incorrectly removes src, it is not remapped by another thread. 397 const auto rest = [&] { 398 void* ptr = mremap(src.ptr(), 0, kPageSize, MREMAP_MAYMOVE | MREMAP_FIXED, 399 dst.ptr()); 400 MaybeSave(); 401 TEST_PCHECK_MSG(ptr != MAP_FAILED, "mremap failed"); 402 TEST_CHECK(ptr == dst.ptr()); 403 TEST_CHECK(IsMapped(src.addr())); 404 TEST_CHECK(IsMapped(dst.addr())); 405 }; 406 EXPECT_THAT(InForkedProcess(rest), IsPosixErrorOkAndHolds(0)); 407 } 408 409 void ExpectAllBytesAre(absl::string_view v, char c) { 410 for (size_t i = 0; i < v.size(); i++) { 411 ASSERT_EQ(v[i], c) << "at offset " << i; 412 } 413 } 414 415 TEST(MremapTest, ExpansionPreservesCOWPagesAndExposesNewFilePages) { 416 // Create a file with 3 pages. The first is filled with 'a', the second is 417 // filled with 'b', and the third is filled with 'c'. 418 TempPath const file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 419 const FileDescriptor fd = 420 ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR)); 421 ASSERT_THAT(WriteFd(fd.get(), std::string(kPageSize, 'a').c_str(), kPageSize), 422 SyscallSucceedsWithValue(kPageSize)); 423 ASSERT_THAT(WriteFd(fd.get(), std::string(kPageSize, 'b').c_str(), kPageSize), 424 SyscallSucceedsWithValue(kPageSize)); 425 ASSERT_THAT(WriteFd(fd.get(), std::string(kPageSize, 'c').c_str(), kPageSize), 426 SyscallSucceedsWithValue(kPageSize)); 427 428 // Create a private mapping of the first 2 pages, and fill the second page 429 // with 'd'. 430 Mapping const src = ASSERT_NO_ERRNO_AND_VALUE(Mmap(nullptr, 2 * kPageSize, 431 PROT_READ | PROT_WRITE, 432 MAP_PRIVATE, fd.get(), 0)); 433 memset(reinterpret_cast<void*>(src.addr() + kPageSize), 'd', kPageSize); 434 MaybeSave(); 435 436 // Move the mapping while expanding it to 3 pages. The resulting mapping 437 // should contain the original first page of the file (filled with 'a'), 438 // followed by the private copy of the second page (filled with 'd'), followed 439 // by the newly-mapped third page of the file (filled with 'c'). 440 Mapping const dst = ASSERT_NO_ERRNO_AND_VALUE( 441 MmapAnon(3 * kPageSize, PROT_NONE, MAP_PRIVATE)); 442 ASSERT_THAT(Mremap(src.ptr(), 2 * kPageSize, 3 * kPageSize, 443 MREMAP_MAYMOVE | MREMAP_FIXED, dst.ptr()), 444 IsPosixErrorOkAndHolds(dst.ptr())); 445 auto const v = dst.view(); 446 ExpectAllBytesAre(v.substr(0, kPageSize), 'a'); 447 ExpectAllBytesAre(v.substr(kPageSize, kPageSize), 'd'); 448 ExpectAllBytesAre(v.substr(2 * kPageSize, kPageSize), 'c'); 449 } 450 451 TEST(MremapDeathTest, SharedAnon) { 452 SetupGvisorDeathTest(); 453 454 // Reserve 4 pages of address space. 455 Mapping const reserved = ASSERT_NO_ERRNO_AND_VALUE( 456 MmapAnon(4 * kPageSize, PROT_NONE, MAP_PRIVATE)); 457 458 // Create a 2-page shared anonymous mapping at the beginning of the 459 // reservation. Fill the first page with 'a' and the second with 'b'. 460 Mapping const m = ASSERT_NO_ERRNO_AND_VALUE( 461 Mmap(reserved.ptr(), 2 * kPageSize, PROT_READ | PROT_WRITE, 462 MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0)); 463 memset(m.ptr(), 'a', kPageSize); 464 memset(reinterpret_cast<void*>(m.addr() + kPageSize), 'b', kPageSize); 465 MaybeSave(); 466 467 // Shrink the mapping to 1 page in-place. 468 ASSERT_THAT(Mremap(m.ptr(), 2 * kPageSize, kPageSize, 0, m.ptr()), 469 IsPosixErrorOkAndHolds(m.ptr())); 470 471 // Expand the mapping to 3 pages, moving it forward by 1 page in the process 472 // since the old and new mappings can't overlap. 473 void* const new_m = reinterpret_cast<void*>(m.addr() + kPageSize); 474 ASSERT_THAT(Mremap(m.ptr(), kPageSize, 3 * kPageSize, 475 MREMAP_MAYMOVE | MREMAP_FIXED, new_m), 476 IsPosixErrorOkAndHolds(new_m)); 477 478 // The first 2 pages of the mapping should still contain the data we wrote 479 // (i.e. shrinking should not have discarded the second page's data), while 480 // touching the third page should raise SIGBUS. 481 auto const v = 482 absl::string_view(static_cast<char const*>(new_m), 3 * kPageSize); 483 ExpectAllBytesAre(v.substr(0, kPageSize), 'a'); 484 ExpectAllBytesAre(v.substr(kPageSize, kPageSize), 'b'); 485 EXPECT_EXIT(ExpectAllBytesAre(v.substr(2 * kPageSize, kPageSize), '\0'), 486 ::testing::KilledBySignal(SIGBUS), ""); 487 } 488 489 } // namespace 490 491 } // namespace testing 492 } // namespace gvisor