address_pool_manager_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/allocator/partition_allocator/address_pool_manager.h"
  5. #include <cstdint>
  6. #include "base/allocator/partition_allocator/address_space_stats.h"
  7. #include "base/allocator/partition_allocator/page_allocator.h"
  8. #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
  9. #include "base/allocator/partition_allocator/partition_alloc_constants.h"
  10. #include "build/build_config.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. namespace partition_alloc::internal {
  13. class AddressSpaceStatsDumperForTesting final : public AddressSpaceStatsDumper {
  14. public:
  15. AddressSpaceStatsDumperForTesting() = default;
  16. ~AddressSpaceStatsDumperForTesting() = default;
  17. void DumpStats(
  18. const partition_alloc::AddressSpaceStats* address_space_stats) override {
  19. regular_pool_usage_ = address_space_stats->regular_pool_stats.usage;
  20. #if defined(PA_HAS_64_BITS_POINTERS)
  21. regular_pool_largest_reservation_ =
  22. address_space_stats->regular_pool_stats.largest_available_reservation;
  23. #endif // defined(PA_HAS_64_BITS_POINTERS)
  24. #if !defined(PA_HAS_64_BITS_POINTERS) && BUILDFLAG(USE_BACKUP_REF_PTR)
  25. blocklist_size_ = address_space_stats->blocklist_size;
  26. #endif // !defined(PA_HAS_64_BITS_POINTERS) && BUILDFLAG(USE_BACKUP_REF_PTR)
  27. }
  28. size_t regular_pool_usage_ = 0;
  29. size_t regular_pool_largest_reservation_ = 0;
  30. size_t blocklist_size_ = 0;
  31. };
  32. #if defined(PA_HAS_64_BITS_POINTERS)
  33. class AddressPoolManagerForTesting : public AddressPoolManager {
  34. public:
  35. AddressPoolManagerForTesting() = default;
  36. ~AddressPoolManagerForTesting() = default;
  37. };
  38. class PartitionAllocAddressPoolManagerTest : public testing::Test {
  39. protected:
  40. PartitionAllocAddressPoolManagerTest() = default;
  41. ~PartitionAllocAddressPoolManagerTest() override = default;
  42. void SetUp() override {
  43. manager_ = std::make_unique<AddressPoolManagerForTesting>();
  44. base_address_ = AllocPages(kPoolSize, kSuperPageSize,
  45. PageAccessibilityConfiguration::kInaccessible,
  46. PageTag::kPartitionAlloc);
  47. ASSERT_TRUE(base_address_);
  48. pool_ = manager_->Add(base_address_, kPoolSize);
  49. }
  50. void TearDown() override {
  51. manager_->Remove(pool_);
  52. FreePages(base_address_, kPoolSize);
  53. manager_.reset();
  54. }
  55. AddressPoolManager* GetAddressPoolManager() { return manager_.get(); }
  56. static constexpr size_t kPoolSize = kPoolMaxSize;
  57. static constexpr size_t kPageCnt = kPoolSize / kSuperPageSize;
  58. std::unique_ptr<AddressPoolManagerForTesting> manager_;
  59. uintptr_t base_address_;
  60. pool_handle pool_;
  61. };
  62. TEST_F(PartitionAllocAddressPoolManagerTest, TooLargePool) {
  63. uintptr_t base_addr = 0x4200000;
  64. EXPECT_DEATH_IF_SUPPORTED(
  65. GetAddressPoolManager()->Add(base_addr, kPoolSize + kSuperPageSize), "");
  66. }
  67. TEST_F(PartitionAllocAddressPoolManagerTest, ManyPages) {
  68. EXPECT_EQ(
  69. GetAddressPoolManager()->Reserve(pool_, 0, kPageCnt * kSuperPageSize),
  70. base_address_);
  71. EXPECT_EQ(GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize), 0u);
  72. GetAddressPoolManager()->UnreserveAndDecommit(pool_, base_address_,
  73. kPageCnt * kSuperPageSize);
  74. EXPECT_EQ(
  75. GetAddressPoolManager()->Reserve(pool_, 0, kPageCnt * kSuperPageSize),
  76. base_address_);
  77. GetAddressPoolManager()->UnreserveAndDecommit(pool_, base_address_,
  78. kPageCnt * kSuperPageSize);
  79. }
  80. TEST_F(PartitionAllocAddressPoolManagerTest, PagesFragmented) {
  81. uintptr_t addrs[kPageCnt];
  82. for (size_t i = 0; i < kPageCnt; ++i) {
  83. addrs[i] = GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize);
  84. EXPECT_EQ(addrs[i], base_address_ + i * kSuperPageSize);
  85. }
  86. EXPECT_EQ(GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize), 0u);
  87. // Free other other super page, so that we have plenty of free space, but none
  88. // of the empty spaces can fit 2 super pages.
  89. for (size_t i = 1; i < kPageCnt; i += 2) {
  90. GetAddressPoolManager()->UnreserveAndDecommit(pool_, addrs[i],
  91. kSuperPageSize);
  92. }
  93. EXPECT_EQ(GetAddressPoolManager()->Reserve(pool_, 0, 2 * kSuperPageSize), 0u);
  94. // Reserve freed super pages back, so that there are no free ones.
  95. for (size_t i = 1; i < kPageCnt; i += 2) {
  96. addrs[i] = GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize);
  97. EXPECT_EQ(addrs[i], base_address_ + i * kSuperPageSize);
  98. }
  99. EXPECT_EQ(GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize), 0u);
  100. // Lastly, clean up.
  101. for (uintptr_t addr : addrs) {
  102. GetAddressPoolManager()->UnreserveAndDecommit(pool_, addr, kSuperPageSize);
  103. }
  104. }
  105. TEST_F(PartitionAllocAddressPoolManagerTest, GetUsedSuperpages) {
  106. uintptr_t addrs[kPageCnt];
  107. for (size_t i = 0; i < kPageCnt; ++i) {
  108. addrs[i] = GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize);
  109. EXPECT_EQ(addrs[i], base_address_ + i * kSuperPageSize);
  110. }
  111. EXPECT_EQ(GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize), 0u);
  112. std::bitset<kMaxSuperPagesInPool> used_super_pages;
  113. GetAddressPoolManager()->GetPoolUsedSuperPages(pool_, used_super_pages);
  114. // We expect every bit to be set.
  115. for (size_t i = 0; i < kPageCnt; ++i) {
  116. ASSERT_TRUE(used_super_pages.test(i));
  117. }
  118. // Free every other super page, so that we have plenty of free space, but none
  119. // of the empty spaces can fit 2 super pages.
  120. for (size_t i = 1; i < kPageCnt; i += 2) {
  121. GetAddressPoolManager()->UnreserveAndDecommit(pool_, addrs[i],
  122. kSuperPageSize);
  123. }
  124. EXPECT_EQ(GetAddressPoolManager()->Reserve(pool_, 0, 2 * kSuperPageSize), 0u);
  125. GetAddressPoolManager()->GetPoolUsedSuperPages(pool_, used_super_pages);
  126. // We expect every other bit to be set.
  127. for (size_t i = 0; i < kPageCnt; i++) {
  128. if (i % 2 == 0) {
  129. ASSERT_TRUE(used_super_pages.test(i));
  130. } else {
  131. ASSERT_FALSE(used_super_pages.test(i));
  132. }
  133. }
  134. // Free the even numbered super pages.
  135. for (size_t i = 0; i < kPageCnt; i += 2) {
  136. GetAddressPoolManager()->UnreserveAndDecommit(pool_, addrs[i],
  137. kSuperPageSize);
  138. }
  139. // Finally check to make sure all bits are zero in the used superpage bitset.
  140. GetAddressPoolManager()->GetPoolUsedSuperPages(pool_, used_super_pages);
  141. for (size_t i = 0; i < kPageCnt; i++) {
  142. ASSERT_FALSE(used_super_pages.test(i));
  143. }
  144. }
  145. TEST_F(PartitionAllocAddressPoolManagerTest, IrregularPattern) {
  146. uintptr_t a1 = GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize);
  147. EXPECT_EQ(a1, base_address_);
  148. uintptr_t a2 = GetAddressPoolManager()->Reserve(pool_, 0, 2 * kSuperPageSize);
  149. EXPECT_EQ(a2, base_address_ + 1 * kSuperPageSize);
  150. uintptr_t a3 = GetAddressPoolManager()->Reserve(pool_, 0, 3 * kSuperPageSize);
  151. EXPECT_EQ(a3, base_address_ + 3 * kSuperPageSize);
  152. uintptr_t a4 = GetAddressPoolManager()->Reserve(pool_, 0, 4 * kSuperPageSize);
  153. EXPECT_EQ(a4, base_address_ + 6 * kSuperPageSize);
  154. uintptr_t a5 = GetAddressPoolManager()->Reserve(pool_, 0, 5 * kSuperPageSize);
  155. EXPECT_EQ(a5, base_address_ + 10 * kSuperPageSize);
  156. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a4, 4 * kSuperPageSize);
  157. uintptr_t a6 = GetAddressPoolManager()->Reserve(pool_, 0, 6 * kSuperPageSize);
  158. EXPECT_EQ(a6, base_address_ + 15 * kSuperPageSize);
  159. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a5, 5 * kSuperPageSize);
  160. uintptr_t a7 = GetAddressPoolManager()->Reserve(pool_, 0, 7 * kSuperPageSize);
  161. EXPECT_EQ(a7, base_address_ + 6 * kSuperPageSize);
  162. uintptr_t a8 = GetAddressPoolManager()->Reserve(pool_, 0, 3 * kSuperPageSize);
  163. EXPECT_EQ(a8, base_address_ + 21 * kSuperPageSize);
  164. uintptr_t a9 = GetAddressPoolManager()->Reserve(pool_, 0, 2 * kSuperPageSize);
  165. EXPECT_EQ(a9, base_address_ + 13 * kSuperPageSize);
  166. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a7, 7 * kSuperPageSize);
  167. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a9, 2 * kSuperPageSize);
  168. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a6, 6 * kSuperPageSize);
  169. uintptr_t a10 =
  170. GetAddressPoolManager()->Reserve(pool_, 0, 15 * kSuperPageSize);
  171. EXPECT_EQ(a10, base_address_ + 6 * kSuperPageSize);
  172. // Clean up.
  173. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a1, kSuperPageSize);
  174. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a2, 2 * kSuperPageSize);
  175. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a3, 3 * kSuperPageSize);
  176. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a8, 3 * kSuperPageSize);
  177. GetAddressPoolManager()->UnreserveAndDecommit(pool_, a10,
  178. 15 * kSuperPageSize);
  179. }
  180. TEST_F(PartitionAllocAddressPoolManagerTest, DecommittedDataIsErased) {
  181. uintptr_t address =
  182. GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize);
  183. ASSERT_TRUE(address);
  184. RecommitSystemPages(address, kSuperPageSize,
  185. PageAccessibilityConfiguration::kReadWrite,
  186. PageAccessibilityDisposition::kRequireUpdate);
  187. memset(reinterpret_cast<void*>(address), 42, kSuperPageSize);
  188. GetAddressPoolManager()->UnreserveAndDecommit(pool_, address, kSuperPageSize);
  189. uintptr_t address2 =
  190. GetAddressPoolManager()->Reserve(pool_, 0, kSuperPageSize);
  191. ASSERT_EQ(address, address2);
  192. RecommitSystemPages(address2, kSuperPageSize,
  193. PageAccessibilityConfiguration::kReadWrite,
  194. PageAccessibilityDisposition::kRequireUpdate);
  195. uint32_t sum = 0;
  196. for (size_t i = 0; i < kSuperPageSize; i++) {
  197. sum += reinterpret_cast<uint8_t*>(address2)[i];
  198. }
  199. EXPECT_EQ(0u, sum) << sum / 42 << " bytes were not zeroed";
  200. GetAddressPoolManager()->UnreserveAndDecommit(pool_, address2,
  201. kSuperPageSize);
  202. }
  203. TEST_F(PartitionAllocAddressPoolManagerTest, RegularPoolUsageChanges) {
  204. AddressSpaceStatsDumperForTesting dumper{};
  205. GetAddressPoolManager()->DumpStats(&dumper);
  206. ASSERT_EQ(dumper.regular_pool_usage_, 0ull);
  207. ASSERT_EQ(dumper.regular_pool_largest_reservation_, kPageCnt);
  208. // Bisect the pool by reserving a super page in the middle.
  209. const uintptr_t midpoint_address =
  210. base_address_ + (kPageCnt / 2) * kSuperPageSize;
  211. ASSERT_EQ(
  212. GetAddressPoolManager()->Reserve(pool_, midpoint_address, kSuperPageSize),
  213. midpoint_address);
  214. GetAddressPoolManager()->DumpStats(&dumper);
  215. ASSERT_EQ(dumper.regular_pool_usage_, 1ull);
  216. ASSERT_EQ(dumper.regular_pool_largest_reservation_, kPageCnt / 2);
  217. GetAddressPoolManager()->UnreserveAndDecommit(pool_, midpoint_address,
  218. kSuperPageSize);
  219. GetAddressPoolManager()->DumpStats(&dumper);
  220. ASSERT_EQ(dumper.regular_pool_usage_, 0ull);
  221. ASSERT_EQ(dumper.regular_pool_largest_reservation_, kPageCnt);
  222. }
  223. #else // defined(PA_HAS_64_BITS_POINTERS)
  224. TEST(PartitionAllocAddressPoolManagerTest, IsManagedByRegularPool) {
  225. constexpr size_t kAllocCount = 8;
  226. static const size_t kNumPages[kAllocCount] = {1, 4, 7, 8, 13, 16, 31, 60};
  227. uintptr_t addrs[kAllocCount];
  228. for (size_t i = 0; i < kAllocCount; ++i) {
  229. addrs[i] = AddressPoolManager::GetInstance().Reserve(
  230. GetRegularPool(), 0,
  231. AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap *
  232. kNumPages[i]);
  233. EXPECT_TRUE(addrs[i]);
  234. EXPECT_TRUE(!(addrs[i] & kSuperPageOffsetMask));
  235. AddressPoolManager::GetInstance().MarkUsed(
  236. GetRegularPool(), addrs[i],
  237. AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap *
  238. kNumPages[i]);
  239. }
  240. for (size_t i = 0; i < kAllocCount; ++i) {
  241. uintptr_t address = addrs[i];
  242. size_t num_pages =
  243. base::bits::AlignUp(
  244. kNumPages[i] *
  245. AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap,
  246. kSuperPageSize) /
  247. AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap;
  248. for (size_t j = 0; j < num_pages; ++j) {
  249. if (j < kNumPages[i]) {
  250. EXPECT_TRUE(AddressPoolManager::IsManagedByRegularPool(address));
  251. } else {
  252. EXPECT_FALSE(AddressPoolManager::IsManagedByRegularPool(address));
  253. }
  254. EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(address));
  255. address += AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap;
  256. }
  257. }
  258. for (size_t i = 0; i < kAllocCount; ++i) {
  259. AddressPoolManager::GetInstance().MarkUnused(
  260. GetRegularPool(), addrs[i],
  261. AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap *
  262. kNumPages[i]);
  263. AddressPoolManager::GetInstance().UnreserveAndDecommit(
  264. GetRegularPool(), addrs[i],
  265. AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap *
  266. kNumPages[i]);
  267. EXPECT_FALSE(AddressPoolManager::IsManagedByRegularPool(addrs[i]));
  268. EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(addrs[i]));
  269. }
  270. }
  271. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  272. TEST(PartitionAllocAddressPoolManagerTest, IsManagedByBRPPool) {
  273. constexpr size_t kAllocCount = 4;
  274. // Totally (1+3+7+11) * 2MB = 44MB allocation
  275. static const size_t kNumPages[kAllocCount] = {1, 3, 7, 11};
  276. uintptr_t addrs[kAllocCount];
  277. for (size_t i = 0; i < kAllocCount; ++i) {
  278. addrs[i] = AddressPoolManager::GetInstance().Reserve(
  279. GetBRPPool(), 0, kSuperPageSize * kNumPages[i]);
  280. EXPECT_TRUE(addrs[i]);
  281. EXPECT_TRUE(!(addrs[i] & kSuperPageOffsetMask));
  282. AddressPoolManager::GetInstance().MarkUsed(GetBRPPool(), addrs[i],
  283. kSuperPageSize * kNumPages[i]);
  284. }
  285. constexpr size_t first_guard_size =
  286. AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap *
  287. AddressPoolManagerBitmap::kGuardOffsetOfBRPPoolBitmap;
  288. constexpr size_t last_guard_size =
  289. AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap *
  290. (AddressPoolManagerBitmap::kGuardBitsOfBRPPoolBitmap -
  291. AddressPoolManagerBitmap::kGuardOffsetOfBRPPoolBitmap);
  292. for (size_t i = 0; i < kAllocCount; ++i) {
  293. uintptr_t address = addrs[i];
  294. size_t num_allocated_size = kNumPages[i] * kSuperPageSize;
  295. size_t num_system_pages = num_allocated_size / SystemPageSize();
  296. for (size_t j = 0; j < num_system_pages; ++j) {
  297. size_t offset = address - addrs[i];
  298. if (offset < first_guard_size ||
  299. offset >= (num_allocated_size - last_guard_size)) {
  300. EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(address));
  301. } else {
  302. EXPECT_TRUE(AddressPoolManager::IsManagedByBRPPool(address));
  303. }
  304. EXPECT_FALSE(AddressPoolManager::IsManagedByRegularPool(address));
  305. address += SystemPageSize();
  306. }
  307. }
  308. for (size_t i = 0; i < kAllocCount; ++i) {
  309. AddressPoolManager::GetInstance().MarkUnused(GetBRPPool(), addrs[i],
  310. kSuperPageSize * kNumPages[i]);
  311. AddressPoolManager::GetInstance().UnreserveAndDecommit(
  312. GetBRPPool(), addrs[i], kSuperPageSize * kNumPages[i]);
  313. EXPECT_FALSE(AddressPoolManager::IsManagedByRegularPool(addrs[i]));
  314. EXPECT_FALSE(AddressPoolManager::IsManagedByBRPPool(addrs[i]));
  315. }
  316. }
  317. #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
  318. TEST(PartitionAllocAddressPoolManagerTest, RegularPoolUsageChanges) {
  319. AddressSpaceStatsDumperForTesting dumper{};
  320. AddressPoolManager::GetInstance().DumpStats(&dumper);
  321. const size_t usage_before = dumper.regular_pool_usage_;
  322. const uintptr_t address = AddressPoolManager::GetInstance().Reserve(
  323. GetRegularPool(), 0, kSuperPageSize);
  324. ASSERT_TRUE(address);
  325. AddressPoolManager::GetInstance().MarkUsed(GetRegularPool(), address,
  326. kSuperPageSize);
  327. AddressPoolManager::GetInstance().DumpStats(&dumper);
  328. EXPECT_GT(dumper.regular_pool_usage_, usage_before);
  329. AddressPoolManager::GetInstance().MarkUnused(GetRegularPool(), address,
  330. kSuperPageSize);
  331. AddressPoolManager::GetInstance().UnreserveAndDecommit(
  332. GetRegularPool(), address, kSuperPageSize);
  333. AddressPoolManager::GetInstance().DumpStats(&dumper);
  334. EXPECT_EQ(dumper.regular_pool_usage_, usage_before);
  335. }
  336. #endif // defined(PA_HAS_64_BITS_POINTERS)
  337. } // namespace partition_alloc::internal