• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/allocator/partition_allocator/partition_alloc.h"
6 
7 #include <string.h>
8 
9 #include <cstdint>
10 #include <memory>
11 
12 #include "base/allocator/partition_allocator/address_pool_manager.h"
13 #include "base/allocator/partition_allocator/memory_reclaimer.h"
14 #include "base/allocator/partition_allocator/partition_address_space.h"
15 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
16 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
17 #include "base/allocator/partition_allocator/partition_alloc_hooks.h"
18 #include "base/allocator/partition_allocator/partition_direct_map_extent.h"
19 #include "base/allocator/partition_allocator/partition_oom.h"
20 #include "base/allocator/partition_allocator/partition_page.h"
21 #include "base/allocator/partition_allocator/partition_root.h"
22 #include "base/allocator/partition_allocator/partition_stats.h"
23 
24 #if BUILDFLAG(USE_STARSCAN)
25 #include "base/allocator/partition_allocator/starscan/pcscan.h"
26 #endif
27 
28 namespace partition_alloc {
29 
PartitionAllocGlobalInit(OomFunction on_out_of_memory)30 void PartitionAllocGlobalInit(OomFunction on_out_of_memory) {
31   // This is from page_allocator_constants.h and doesn't really fit here, but
32   // there isn't a centralized initialization function in page_allocator.cc, so
33   // there's no good place in that file to do a STATIC_ASSERT_OR_PA_CHECK.
34   STATIC_ASSERT_OR_PA_CHECK(
35       (internal::SystemPageSize() & internal::SystemPageOffsetMask()) == 0,
36       "SystemPageSize() must be power of 2");
37 
38   // Two partition pages are used as guard / metadata page so make sure the
39   // super page size is bigger.
40   STATIC_ASSERT_OR_PA_CHECK(
41       internal::PartitionPageSize() * 4 <= internal::kSuperPageSize,
42       "ok super page size");
43   STATIC_ASSERT_OR_PA_CHECK(
44       (internal::kSuperPageSize & internal::SystemPageOffsetMask()) == 0,
45       "ok super page multiple");
46   // Four system pages gives us room to hack out a still-guard-paged piece
47   // of metadata in the middle of a guard partition page.
48   STATIC_ASSERT_OR_PA_CHECK(
49       internal::SystemPageSize() * 4 <= internal::PartitionPageSize(),
50       "ok partition page size");
51   STATIC_ASSERT_OR_PA_CHECK(
52       (internal::PartitionPageSize() & internal::SystemPageOffsetMask()) == 0,
53       "ok partition page multiple");
54   static_assert(sizeof(internal::PartitionPage<internal::ThreadSafe>) <=
55                     internal::kPageMetadataSize,
56                 "PartitionPage should not be too big");
57   STATIC_ASSERT_OR_PA_CHECK(
58       internal::kPageMetadataSize * internal::NumPartitionPagesPerSuperPage() <=
59           internal::SystemPageSize(),
60       "page metadata fits in hole");
61 
62   // Limit to prevent callers accidentally overflowing an int size.
63   STATIC_ASSERT_OR_PA_CHECK(
64       internal::MaxDirectMapped() <=
65           (1UL << 31) + internal::DirectMapAllocationGranularity(),
66       "maximum direct mapped allocation");
67 
68   // Check that some of our zanier calculations worked out as expected.
69   static_assert(internal::kSmallestBucket == internal::kAlignment,
70                 "generic smallest bucket");
71   static_assert(internal::kMaxBucketed == 983040, "generic max bucketed");
72   STATIC_ASSERT_OR_PA_CHECK(
73       internal::MaxSystemPagesPerRegularSlotSpan() <= 16,
74       "System pages per slot span must be no greater than 16.");
75 
76 #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
77   STATIC_ASSERT_OR_PA_CHECK(
78       internal::GetPartitionRefCountIndexMultiplierShift() <
79           std::numeric_limits<size_t>::max() / 2,
80       "Calculation in GetPartitionRefCountIndexMultiplierShift() must not "
81       "underflow.");
82   // Check that the GetPartitionRefCountIndexMultiplierShift() calculation is
83   // correct.
84   STATIC_ASSERT_OR_PA_CHECK(
85       (1 << internal::GetPartitionRefCountIndexMultiplierShift()) ==
86           (internal::SystemPageSize() /
87            (sizeof(internal::PartitionRefCount) *
88             (internal::kSuperPageSize / internal::SystemPageSize()))),
89       "Bitshift must match the intended multiplication.");
90   STATIC_ASSERT_OR_PA_CHECK(
91       ((sizeof(internal::PartitionRefCount) *
92         (internal::kSuperPageSize / internal::SystemPageSize()))
93        << internal::GetPartitionRefCountIndexMultiplierShift()) <=
94           internal::SystemPageSize(),
95       "PartitionRefCount Bitmap size must be smaller than or equal to "
96       "<= SystemPageSize().");
97 #endif  // BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
98 
99   PA_DCHECK(on_out_of_memory);
100   internal::g_oom_handling_function = on_out_of_memory;
101 }
102 
PartitionAllocGlobalUninitForTesting()103 void PartitionAllocGlobalUninitForTesting() {
104 #if BUILDFLAG(ENABLE_PKEYS)
105   internal::PartitionAddressSpace::UninitPkeyPoolForTesting();
106 #endif
107   internal::g_oom_handling_function = nullptr;
108 }
109 
110 namespace internal {
111 
112 template <bool thread_safe>
~PartitionAllocator()113 PartitionAllocator<thread_safe>::~PartitionAllocator() {
114   MemoryReclaimer::Instance()->UnregisterPartition(&partition_root_);
115 }
116 
117 template <bool thread_safe>
init(PartitionOptions opts)118 void PartitionAllocator<thread_safe>::init(PartitionOptions opts) {
119 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
120   PA_CHECK(opts.thread_cache == PartitionOptions::ThreadCache::kDisabled)
121       << "Cannot use a thread cache when PartitionAlloc is malloc().";
122 #endif
123   partition_root_.Init(opts);
124   MemoryReclaimer::Instance()->RegisterPartition(&partition_root_);
125 }
126 
127 template PartitionAllocator<internal::ThreadSafe>::~PartitionAllocator();
128 template void PartitionAllocator<internal::ThreadSafe>::init(PartitionOptions);
129 
130 #if (BUILDFLAG(PA_DCHECK_IS_ON) ||                    \
131      BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)) && \
132     BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
CheckThatSlotOffsetIsZero(uintptr_t address)133 void CheckThatSlotOffsetIsZero(uintptr_t address) {
134   // Add kPartitionPastAllocationAdjustment, because
135   // PartitionAllocGetSlotStartInBRPPool will subtract it.
136   PA_CHECK(PartitionAllocGetSlotStartInBRPPool(
137                address + kPartitionPastAllocationAdjustment) == address);
138 }
139 #endif
140 
141 }  // namespace internal
142 
143 }  // namespace partition_alloc
144