address_pool_manager_bitmap.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright 2021 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. #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_POOL_MANAGER_BITMAP_H_
  5. #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_POOL_MANAGER_BITMAP_H_
  6. #include <array>
  7. #include <atomic>
  8. #include <bitset>
  9. #include <limits>
  10. #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
  11. #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
  12. #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
  13. #include "base/allocator/partition_allocator/partition_alloc_check.h"
  14. #include "base/allocator/partition_allocator/partition_alloc_config.h"
  15. #include "base/allocator/partition_allocator/partition_alloc_constants.h"
  16. #include "base/allocator/partition_allocator/partition_lock.h"
  17. #include "build/build_config.h"
  18. #if !defined(PA_HAS_64_BITS_POINTERS)
  19. namespace partition_alloc {
  20. namespace internal {
  21. // AddressPoolManagerBitmap is a set of bitmaps that track whether a given
  22. // address is in a pool that supports BackupRefPtr, or in a pool that doesn't
  23. // support it. All PartitionAlloc allocations must be in either of the pools.
  24. //
  25. // This code is specific to 32-bit systems.
  26. class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManagerBitmap {
  27. public:
  28. static constexpr uint64_t kGiB = 1024 * 1024 * 1024ull;
  29. static constexpr uint64_t kAddressSpaceSize = 4ull * kGiB;
  30. // For BRP pool, we use partition page granularity to eliminate the guard
  31. // pages from the bitmap at the ends:
  32. // - Eliminating the guard page at the beginning is needed so that pointers
  33. // to the end of an allocation that immediately precede a super page in BRP
  34. // pool don't accidentally fall into that pool.
  35. // - Eliminating the guard page at the end is to ensure that the last page
  36. // of the address space isn't in the BRP pool. This allows using sentinels
  37. // like reinterpret_cast<void*>(-1) without a risk of triggering BRP logic
  38. // on an invalid address. (Note, 64-bit systems don't have this problem as
  39. // the upper half of the address space always belongs to the OS.)
  40. //
  41. // Note, direct map allocations also belong to this pool. The same logic as
  42. // above applies. It is important to note, however, that the granularity used
  43. // here has to be a minimum of partition page size and direct map allocation
  44. // granularity. Since DirectMapAllocationGranularity() is no smaller than
  45. // PageAllocationGranularity(), we don't need to decrease the bitmap
  46. // granularity any further.
  47. static constexpr size_t kBitShiftOfBRPPoolBitmap = PartitionPageShift();
  48. static constexpr size_t kBytesPer1BitOfBRPPoolBitmap = PartitionPageSize();
  49. static_assert(kBytesPer1BitOfBRPPoolBitmap == 1 << kBitShiftOfBRPPoolBitmap,
  50. "");
  51. static constexpr size_t kGuardOffsetOfBRPPoolBitmap = 1;
  52. static constexpr size_t kGuardBitsOfBRPPoolBitmap = 2;
  53. static constexpr size_t kBRPPoolBits =
  54. kAddressSpaceSize / kBytesPer1BitOfBRPPoolBitmap;
  55. // Regular pool may include both normal bucket and direct map allocations, so
  56. // the bitmap granularity has to be at least as small as
  57. // DirectMapAllocationGranularity(). No need to eliminate guard pages at the
  58. // ends, as this is a BackupRefPtr-specific concern, hence no need to lower
  59. // the granularity to partition page size.
  60. static constexpr size_t kBitShiftOfRegularPoolBitmap =
  61. DirectMapAllocationGranularityShift();
  62. static constexpr size_t kBytesPer1BitOfRegularPoolBitmap =
  63. DirectMapAllocationGranularity();
  64. static_assert(kBytesPer1BitOfRegularPoolBitmap ==
  65. 1 << kBitShiftOfRegularPoolBitmap,
  66. "");
  67. static constexpr size_t kRegularPoolBits =
  68. kAddressSpaceSize / kBytesPer1BitOfRegularPoolBitmap;
  69. // Returns false for nullptr.
  70. static bool IsManagedByRegularPool(uintptr_t address) {
  71. static_assert(
  72. std::numeric_limits<uintptr_t>::max() >> kBitShiftOfRegularPoolBitmap <
  73. regular_pool_bits_.size(),
  74. "The bitmap is too small, will result in unchecked out of bounds "
  75. "accesses.");
  76. // It is safe to read |regular_pool_bits_| without a lock since the caller
  77. // is responsible for guaranteeing that the address is inside a valid
  78. // allocation and the deallocation call won't race with this call.
  79. return PA_TS_UNCHECKED_READ(
  80. regular_pool_bits_)[address >> kBitShiftOfRegularPoolBitmap];
  81. }
  82. // Returns false for nullptr.
  83. static bool IsManagedByBRPPool(uintptr_t address) {
  84. static_assert(std::numeric_limits<uintptr_t>::max() >>
  85. kBitShiftOfBRPPoolBitmap < brp_pool_bits_.size(),
  86. "The bitmap is too small, will result in unchecked out of "
  87. "bounds accesses.");
  88. // It is safe to read |brp_pool_bits_| without a lock since the caller
  89. // is responsible for guaranteeing that the address is inside a valid
  90. // allocation and the deallocation call won't race with this call.
  91. return PA_TS_UNCHECKED_READ(
  92. brp_pool_bits_)[address >> kBitShiftOfBRPPoolBitmap];
  93. }
  94. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  95. static void BanSuperPageFromBRPPool(uintptr_t address) {
  96. brp_forbidden_super_page_map_[address >> kSuperPageShift].store(
  97. true, std::memory_order_relaxed);
  98. }
  99. static bool IsAllowedSuperPageForBRPPool(uintptr_t address) {
  100. // The only potentially dangerous scenario, in which this check is used, is
  101. // when the assignment of the first raw_ptr<T> object for a non-GigaCage
  102. // address is racing with the allocation of a new GigCage super-page at the
  103. // same address. We assume that if raw_ptr<T> is being initialized with a
  104. // raw pointer, the associated allocation is "alive"; otherwise, the issue
  105. // should be fixed by rewriting the raw pointer variable as raw_ptr<T>.
  106. // In the worst case, when such a fix is impossible, we should just undo the
  107. // raw pointer -> raw_ptr<T> rewrite of the problematic field. If the
  108. // above assumption holds, the existing allocation will prevent us from
  109. // reserving the super-page region and, thus, having the race condition.
  110. // Since we rely on that external synchronization, the relaxed memory
  111. // ordering should be sufficient.
  112. return !brp_forbidden_super_page_map_[address >> kSuperPageShift].load(
  113. std::memory_order_relaxed);
  114. }
  115. static void IncrementBlocklistHitCount() { ++blocklist_hit_count_; }
  116. #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
  117. private:
  118. friend class AddressPoolManager;
  119. static Lock& GetLock();
  120. static std::bitset<kRegularPoolBits> regular_pool_bits_
  121. PA_GUARDED_BY(GetLock());
  122. static std::bitset<kBRPPoolBits> brp_pool_bits_ PA_GUARDED_BY(GetLock());
  123. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  124. static std::array<std::atomic_bool, kAddressSpaceSize / kSuperPageSize>
  125. brp_forbidden_super_page_map_;
  126. static std::atomic_size_t blocklist_hit_count_;
  127. #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
  128. };
  129. } // namespace internal
  130. // Returns false for nullptr.
  131. PA_ALWAYS_INLINE bool IsManagedByPartitionAlloc(uintptr_t address) {
  132. // When USE_BACKUP_REF_PTR is off, BRP pool isn't used.
  133. // No need to add IsManagedByConfigurablePool, because Configurable Pool
  134. // doesn't exist on 32-bit.
  135. #if !BUILDFLAG(USE_BACKUP_REF_PTR)
  136. PA_DCHECK(!internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address));
  137. #endif
  138. return internal::AddressPoolManagerBitmap::IsManagedByRegularPool(address)
  139. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  140. || internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address)
  141. #endif
  142. ;
  143. }
  144. // Returns false for nullptr.
  145. PA_ALWAYS_INLINE bool IsManagedByPartitionAllocRegularPool(uintptr_t address) {
  146. return internal::AddressPoolManagerBitmap::IsManagedByRegularPool(address);
  147. }
  148. // Returns false for nullptr.
  149. PA_ALWAYS_INLINE bool IsManagedByPartitionAllocBRPPool(uintptr_t address) {
  150. return internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address);
  151. }
  152. // Returns false for nullptr.
  153. PA_ALWAYS_INLINE bool IsManagedByPartitionAllocConfigurablePool(
  154. uintptr_t address) {
  155. // The Configurable Pool is only available on 64-bit builds.
  156. return false;
  157. }
  158. PA_ALWAYS_INLINE bool IsConfigurablePoolAvailable() {
  159. // The Configurable Pool is only available on 64-bit builds.
  160. return false;
  161. }
  162. } // namespace partition_alloc
  163. #endif // !defined(PA_HAS_64_BITS_POINTERS)
  164. #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_POOL_MANAGER_BITMAP_H_