123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <fcntl.h>
- #include <stdint.h>
- #include <sys/mman.h>
- #include <memory>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/callback_helpers.h"
- #include "base/files/scoped_file.h"
- #include "base/memory/madv_free_discardable_memory_allocator_posix.h"
- #include "base/memory/madv_free_discardable_memory_posix.h"
- #include "base/memory/page_size.h"
- #include "build/build_config.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #define SUCCEED_IF_MADV_FREE_UNSUPPORTED() \
- do { \
- if (GetMadvFreeSupport() != base::MadvFreeSupport::kSupported) { \
- SUCCEED() \
- << "MADV_FREE is not supported (Linux 4.5+ required), vacuously " \
- "passing test"; \
- return; \
- } \
- } while (0)
- namespace base {
- std::atomic<size_t> allocator_byte_count;
- class MadvFreeDiscardableMemoryPosixTester
- : public MadvFreeDiscardableMemoryPosix {
- public:
- MadvFreeDiscardableMemoryPosixTester(size_t size_in_bytes)
- : MadvFreeDiscardableMemoryPosix(size_in_bytes, &allocator_byte_count) {}
- using MadvFreeDiscardableMemoryPosix::DiscardPage;
- using MadvFreeDiscardableMemoryPosix::GetPageCount;
- using MadvFreeDiscardableMemoryPosix::IsLockedForTesting;
- using MadvFreeDiscardableMemoryPosix::IsValid;
- using MadvFreeDiscardableMemoryPosix::SetKeepMemoryForTesting;
- };
- class MadvFreeDiscardableMemoryTest : public ::testing::Test {
- protected:
- MadvFreeDiscardableMemoryTest() {}
- ~MadvFreeDiscardableMemoryTest() override {}
- const size_t kPageSize = base::GetPageSize();
- std::unique_ptr<MadvFreeDiscardableMemoryPosixTester>
- AllocateLockedDiscardableMemoryPagesForTest(size_t size_in_pages) {
- return std::make_unique<MadvFreeDiscardableMemoryPosixTester>(
- size_in_pages * kPageSize);
- }
- };
- using MadvFreeDiscardableMemoryDeathTest = MadvFreeDiscardableMemoryTest;
- constexpr char kTestPattern[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- TEST_F(MadvFreeDiscardableMemoryTest, AllocateAndUse) {
- SUCCEED_IF_MADV_FREE_UNSUPPORTED();
- std::unique_ptr<MadvFreeDiscardableMemoryPosixTester> mem =
- AllocateLockedDiscardableMemoryPagesForTest(1);
- mem->SetKeepMemoryForTesting(true);
- ASSERT_TRUE(mem->IsValid());
- ASSERT_TRUE(mem->IsLockedForTesting());
- char buffer[sizeof(kTestPattern)];
- // Write test pattern to block
- uint8_t* data = mem->data_as<uint8_t>();
- memcpy(data, kTestPattern, sizeof(kTestPattern));
- // Read test pattern from block
- data = mem->data_as<uint8_t>();
- memcpy(buffer, data, sizeof(kTestPattern));
- EXPECT_EQ(memcmp(kTestPattern, buffer, sizeof(kTestPattern)), 0);
- // Memory contents should not change after successful unlock and lock.
- mem->Unlock();
- ASSERT_TRUE(mem->Lock());
- EXPECT_EQ(memcmp(kTestPattern, buffer, sizeof(kTestPattern)), 0);
- }
- TEST_F(MadvFreeDiscardableMemoryTest, LockAndUnlock) {
- SUCCEED_IF_MADV_FREE_UNSUPPORTED();
- const size_t kPageCount = 10;
- std::unique_ptr<MadvFreeDiscardableMemoryPosixTester> mem =
- AllocateLockedDiscardableMemoryPagesForTest(kPageCount);
- ASSERT_TRUE(mem->IsValid());
- ASSERT_TRUE(mem->IsLockedForTesting());
- memset(mem->data(), 0xE7, kPageSize * kPageCount);
- mem->Unlock();
- ASSERT_FALSE(mem->IsLockedForTesting());
- bool result = mem->Lock();
- // If Lock() succeeded, the memory region should be valid. If Lock() failed,
- // the memory region should be invalid.
- ASSERT_EQ(result, mem->IsValid());
- }
- TEST_F(MadvFreeDiscardableMemoryTest, LockShouldFailAfterDiscard) {
- SUCCEED_IF_MADV_FREE_UNSUPPORTED();
- constexpr size_t kPageCount = 10;
- std::unique_ptr<MadvFreeDiscardableMemoryPosixTester> mem =
- AllocateLockedDiscardableMemoryPagesForTest(kPageCount);
- uint8_t* data = mem->data_as<uint8_t>();
- ASSERT_TRUE(mem->IsValid());
- ASSERT_TRUE(mem->IsLockedForTesting());
- // Modify block data such that at least one page is non-zero.
- memset(data, 0xff, kPageSize * kPageCount);
- mem->Unlock();
- ASSERT_FALSE(mem->IsLockedForTesting());
- // Forcefully discard at least one non-zero page.
- mem->DiscardPage(5);
- // Locking when a page has been discarded should fail.
- ASSERT_FALSE(mem->Lock());
- // Locking after memory is deallocated should fail.
- ASSERT_FALSE(mem->Lock());
- // Check that memory has been deallocated.
- ASSERT_FALSE(mem->IsValid());
- }
- } // namespace base
|