diff --git a/util/posix/scoped_mmap.cc b/util/posix/scoped_mmap.cc index 0965fd67..fbf47fae 100644 --- a/util/posix/scoped_mmap.cc +++ b/util/posix/scoped_mmap.cc @@ -33,6 +33,11 @@ bool Munmap(uintptr_t addr, size_t len) { return true; } +size_t RoundPage(size_t size) { + const size_t kPageMask = base::checked_cast(getpagesize()) - 1; + return (size + kPageMask) & ~kPageMask; +} + } // namespace namespace crashpad { @@ -41,7 +46,7 @@ ScopedMmap::ScopedMmap() {} ScopedMmap::~ScopedMmap() { if (is_valid()) { - Munmap(reinterpret_cast(addr_), len_); + Munmap(reinterpret_cast(addr_), RoundPage(len_)); } } @@ -51,29 +56,28 @@ bool ScopedMmap::Reset() { bool ScopedMmap::ResetAddrLen(void* addr, size_t len) { const uintptr_t new_addr = reinterpret_cast(addr); + const size_t new_len_round = RoundPage(len); if (addr == MAP_FAILED) { DCHECK_EQ(len, 0u); } else { - // Round |len| up to the next page. - const size_t kPageMask = base::checked_cast(getpagesize()) - 1; - len = (len + kPageMask) & ~kPageMask; - DCHECK_NE(len, 0u); DCHECK_EQ(new_addr % getpagesize(), 0u); - DCHECK((base::CheckedNumeric(new_addr) + (len - 1)).IsValid()); + DCHECK((base::CheckedNumeric(new_addr) + (new_len_round - 1)) + .IsValid()); } bool result = true; if (is_valid()) { const uintptr_t old_addr = reinterpret_cast(addr_); + const size_t old_len_round = RoundPage(len_); if (old_addr < new_addr) { - result &= Munmap(old_addr, std::min(len_, new_addr - old_addr)); + result &= Munmap(old_addr, std::min(old_len_round, new_addr - old_addr)); } - if (old_addr + len_ > new_addr + len) { - uintptr_t unmap_start = std::max(old_addr, new_addr + len); - result &= Munmap(unmap_start, old_addr + len_ - unmap_start); + if (old_addr + old_len_round > new_addr + new_len_round) { + uintptr_t unmap_start = std::max(old_addr, new_addr + new_len_round); + result &= Munmap(unmap_start, old_addr + old_len_round - unmap_start); } } @@ -108,7 +112,7 @@ bool ScopedMmap::ResetMmap(void* addr, } bool ScopedMmap::Mprotect(int prot) { - if (mprotect(addr_, len_, prot) < 0) { + if (mprotect(addr_, RoundPage(len_), prot) < 0) { PLOG(ERROR) << "mprotect"; return false; } diff --git a/util/posix/scoped_mmap.h b/util/posix/scoped_mmap.h index b0ff3dc0..9f22372b 100644 --- a/util/posix/scoped_mmap.h +++ b/util/posix/scoped_mmap.h @@ -91,6 +91,11 @@ class ScopedMmap { } //! \brief Returns the size of the memory-mapped region. + //! + //! This is the value originally passed to ResetAddrLen() or ResetMmap(), or + //! after Reset(), `0`. It may not be a round number of pages. Providing the + //! passed-in value is intended to ease tracking the intended lengths of + //! memory-mapped regions backed by files whose sizes are not whole pages. size_t len() const { return len_; } private: diff --git a/util/posix/scoped_mmap_test.cc b/util/posix/scoped_mmap_test.cc index e32fa159..5279fdb8 100644 --- a/util/posix/scoped_mmap_test.cc +++ b/util/posix/scoped_mmap_test.cc @@ -309,7 +309,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(ScopedMmapResetMmap(&mapping, kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_NE(mapping.addr(), MAP_FAILED); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kHalfPageSize); TestCookie cookie; cookie.SetUp(mapping.addr_as()); @@ -319,7 +319,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kHalfPageSize); EXPECT_EQ(cookie.Observed(), cookie.Expected()); @@ -328,14 +328,14 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, 1)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), 1u); EXPECT_EQ(cookie.Observed(), cookie.Expected()); ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize - 1)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kPageSize - 1); EXPECT_EQ(cookie.Observed(), cookie.Expected()); @@ -356,7 +356,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kHalfPageSize); EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected()); EXPECT_DEATH_CRASH(two_cookies[1].Check(), ""); @@ -376,7 +376,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize + kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), 2 * kPageSize); + EXPECT_EQ(mapping.len(), kPageSize + kHalfPageSize); EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected()); EXPECT_EQ(two_cookies[1].Observed(), two_cookies[1].Expected());