• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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/src/partition_alloc/partition_root.h"
6 #include "testing/gtest/include/gtest/gtest.h"
7 
8 #include "base/allocator/dispatcher/configuration.h"
9 #include "base/allocator/dispatcher/dispatcher.h"
10 #include "base/allocator/dispatcher/testing/dispatcher_test.h"
11 #include "base/allocator/dispatcher/testing/tools.h"
12 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_buildflags.h"
13 #include "build/build_config.h"
14 
15 #if BUILDFLAG(USE_PARTITION_ALLOC)
16 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_for_testing.h"
17 #endif
18 
19 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
20 #include "base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h"
21 #endif
22 
23 #include <tuple>
24 
25 namespace base::allocator::dispatcher {
26 namespace {
27 using configuration::kMaximumNumberOfObservers;
28 using configuration::kMaximumNumberOfOptionalObservers;
29 using partition_alloc::PartitionOptions;
30 using partition_alloc::PartitionRoot;
31 using testing::DispatcherTest;
32 
33 // A simple observer implementation. Since these tests plug in to Partition
34 // Allocator and Allocator Shim, implementing an observer with Google Mock
35 // results in endless recursion.
36 struct ObserverMock {
OnAllocationbase::allocator::dispatcher::__anonec3d7a490111::ObserverMock37   void OnAllocation(void* address,
38                     size_t size,
39                     AllocationSubsystem sub_system,
40                     const char* type_name) {
41     ++on_allocation_calls_;
42   }
OnFreebase::allocator::dispatcher::__anonec3d7a490111::ObserverMock43   void OnFree(void* address) { ++on_free_calls_; }
44 
Resetbase::allocator::dispatcher::__anonec3d7a490111::ObserverMock45   void Reset() {
46     on_allocation_calls_ = 0;
47     on_free_calls_ = 0;
48   }
49 
GetNumberOnAllocationCallsbase::allocator::dispatcher::__anonec3d7a490111::ObserverMock50   size_t GetNumberOnAllocationCalls() const { return on_allocation_calls_; }
GetNumberOnFreeCallsbase::allocator::dispatcher::__anonec3d7a490111::ObserverMock51   size_t GetNumberOnFreeCalls() const { return on_free_calls_; }
52 
53  private:
54   size_t on_allocation_calls_ = 0;
55   size_t on_free_calls_ = 0;
56 };
57 
58 struct DispatcherInitializerGuard {
59   template <typename... Observers>
DispatcherInitializerGuardbase::allocator::dispatcher::__anonec3d7a490111::DispatcherInitializerGuard60   explicit DispatcherInitializerGuard(std::tuple<Observers*...> observers) {
61     Dispatcher::GetInstance().Initialize(observers);
62   }
63 
~DispatcherInitializerGuardbase::allocator::dispatcher::__anonec3d7a490111::DispatcherInitializerGuard64   ~DispatcherInitializerGuard() { Dispatcher::GetInstance().ResetForTesting(); }
65 };
66 
67 struct BaseAllocatorDispatcherTest : public DispatcherTest {};
68 
69 template <typename A>
DoBasicTest(A & allocator)70 void DoBasicTest(A& allocator) {
71   // All we want to verify is that the Dispatcher correctly hooks into the
72   // passed allocator. Therefore, we do not perform an exhaustive test but
73   // just check some basics.
74   std::array<ObserverMock, kMaximumNumberOfObservers> observers;
75 
76   {
77     DispatcherInitializerGuard const g(
78         testing::CreateTupleOfPointers(observers));
79 
80     constexpr size_t size_to_allocate = 1024;
81     void* const ptr = allocator.Alloc(size_to_allocate);
82     allocator.Free(ptr);
83   }
84 
85   for (const auto& mock : observers) {
86     EXPECT_GE(mock.GetNumberOnAllocationCalls(), 1u);
87     EXPECT_GE(mock.GetNumberOnFreeCalls(), 1u);
88   }
89 }
90 
TEST_F(BaseAllocatorDispatcherTest,VerifyInitialization)91 TEST_F(BaseAllocatorDispatcherTest, VerifyInitialization) {
92   std::array<ObserverMock, kMaximumNumberOfObservers> observers;
93 
94   DispatcherInitializerGuard g(testing::CreateTupleOfPointers(observers));
95 }
96 
97 #if BUILDFLAG(USE_PARTITION_ALLOC) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
98 // Don't enable this test when MEMORY_TOOL_REPLACES_ALLOCATOR is defined,
99 // because it makes PartitionAlloc take a different path that doesn't provide
100 // notifications to observer hooks.
101 struct PartitionAllocator {
Allocbase::allocator::dispatcher::__anonec3d7a490111::PartitionAllocator102   void* Alloc(size_t size) { return alloc_.AllocInline(size); }
Freebase::allocator::dispatcher::__anonec3d7a490111::PartitionAllocator103   void Free(void* data) { alloc_.Free(data); }
~PartitionAllocatorbase::allocator::dispatcher::__anonec3d7a490111::PartitionAllocator104   ~PartitionAllocator() {
105     // Use |DisallowLeaks| to confirm that there is no memory allocated and
106     // not yet freed.
107     alloc_.ResetForTesting(::partition_alloc::internal::DisallowLeaks);
108   }
109 
110  private:
111   PartitionRoot alloc_{PartitionOptions{}};
112 };
113 
TEST_F(BaseAllocatorDispatcherTest,VerifyNotificationUsingPartitionAllocator)114 TEST_F(BaseAllocatorDispatcherTest, VerifyNotificationUsingPartitionAllocator) {
115   PartitionAllocator allocator;
116   DoBasicTest(allocator);
117 }
118 #endif
119 
120 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
121 struct AllocatorShimAllocator {
Allocbase::allocator::dispatcher::__anonec3d7a490111::AllocatorShimAllocator122   void* Alloc(size_t size) { return allocator_shim::UncheckedAlloc(size); }
Freebase::allocator::dispatcher::__anonec3d7a490111::AllocatorShimAllocator123   void Free(void* data) { allocator_shim::UncheckedFree(data); }
124 };
125 
126 #if BUILDFLAG(IS_APPLE) && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
127 // Disable the test when running on any of Apple's OSs without PartitionAlloc
128 // being the default allocator. In this case, all allocations are routed to
129 // MallocImpl, which then causes the test to terminate unexpectedly.
130 #define MAYBE_VerifyNotificationUsingAllocatorShim \
131   DISABLED_VerifyNotificationUsingAllocatorShim
132 #else
133 #define MAYBE_VerifyNotificationUsingAllocatorShim \
134   VerifyNotificationUsingAllocatorShim
135 #endif
136 
TEST_F(BaseAllocatorDispatcherTest,MAYBE_VerifyNotificationUsingAllocatorShim)137 TEST_F(BaseAllocatorDispatcherTest, MAYBE_VerifyNotificationUsingAllocatorShim) {
138   AllocatorShimAllocator allocator;
139   DoBasicTest(allocator);
140 }
141 #endif
142 
143 }  // namespace
144 }  // namespace base::allocator::dispatcher
145