dispatcher_unittest.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // Copyright (c) 2022 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 "testing/gtest/include/gtest/gtest.h"
  5. #include "base/allocator/buildflags.h"
  6. #include "base/allocator/dispatcher/configuration.h"
  7. #include "base/allocator/dispatcher/dispatcher.h"
  8. #include "base/allocator/dispatcher/testing/dispatcher_test.h"
  9. #include "base/allocator/dispatcher/testing/tools.h"
  10. #include "build/build_config.h"
  11. #if BUILDFLAG(USE_PARTITION_ALLOC)
  12. #include "base/allocator/partition_allocator/partition_alloc.h"
  13. #endif
  14. #if BUILDFLAG(USE_ALLOCATOR_SHIM)
  15. #include "base/allocator/allocator_shim.h"
  16. #endif
  17. #include <tuple>
  18. namespace base::allocator::dispatcher {
  19. namespace {
  20. using configuration::kMaximumNumberOfObservers;
  21. using configuration::kMaximumNumberOfOptionalObservers;
  22. using partition_alloc::PartitionOptions;
  23. using partition_alloc::ThreadSafePartitionRoot;
  24. using testing::DispatcherTest;
  25. // A simple observer implementation. Since these tests plug in to Partition
  26. // Allocator and Allocator Shim, implementing an observer with Google Mock
  27. // results in endless recursion.
  28. struct ObserverMock {
  29. void OnAllocation(void* address,
  30. size_t size,
  31. AllocationSubsystem sub_system,
  32. const char* type_name) {
  33. ++on_allocation_calls_;
  34. }
  35. void OnFree(void* address) { ++on_free_calls_; }
  36. void Reset() {
  37. on_allocation_calls_ = 0;
  38. on_free_calls_ = 0;
  39. }
  40. size_t GetNumberOnAllocationCalls() const { return on_allocation_calls_; }
  41. size_t GetNumberOnFreeCalls() const { return on_free_calls_; }
  42. private:
  43. size_t on_allocation_calls_ = 0;
  44. size_t on_free_calls_ = 0;
  45. };
  46. struct DispatcherInitializerGuard {
  47. template <typename... Observers>
  48. explicit DispatcherInitializerGuard(std::tuple<Observers*...> observers) {
  49. Dispatcher::GetInstance().Initialize(observers);
  50. }
  51. ~DispatcherInitializerGuard() { Dispatcher::GetInstance().ResetForTesting(); }
  52. };
  53. struct BaseAllocatorDispatcherTest : public DispatcherTest {};
  54. template <typename A>
  55. void DoBasicTest(A& allocator) {
  56. // All we want to verify is that the Dispatcher correctly hooks into the
  57. // passed allocator. Therefore, we do not perform an exhaustive test but
  58. // just check some basics.
  59. std::array<ObserverMock, kMaximumNumberOfObservers> observers;
  60. {
  61. DispatcherInitializerGuard const g(
  62. testing::CreateTupleOfPointers(observers));
  63. constexpr size_t size_to_allocate = 1024;
  64. void* const ptr = allocator.Alloc(size_to_allocate);
  65. allocator.Free(ptr);
  66. }
  67. for (const auto& mock : observers) {
  68. EXPECT_GE(mock.GetNumberOnAllocationCalls(), 1u);
  69. EXPECT_GE(mock.GetNumberOnFreeCalls(), 1u);
  70. }
  71. }
  72. TEST_F(BaseAllocatorDispatcherTest, VerifyInitialization) {
  73. std::array<ObserverMock, kMaximumNumberOfObservers> observers;
  74. DispatcherInitializerGuard g(testing::CreateTupleOfPointers(observers));
  75. }
  76. #if BUILDFLAG(USE_PARTITION_ALLOC) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
  77. // Don't enable this test when MEMORY_TOOL_REPLACES_ALLOCATOR is defined,
  78. // because it makes PartitionAlloc take a different path that doesn't provide
  79. // notifications to observer hooks.
  80. struct PartitionAllocator {
  81. void* Alloc(size_t size) { return alloc_.AllocWithFlags(0, size, nullptr); }
  82. void Free(void* data) { alloc_.Free(data); }
  83. private:
  84. ThreadSafePartitionRoot alloc_{{
  85. PartitionOptions::AlignedAlloc::kDisallowed,
  86. PartitionOptions::ThreadCache::kDisabled,
  87. PartitionOptions::Quarantine::kDisallowed,
  88. PartitionOptions::Cookie::kAllowed,
  89. PartitionOptions::BackupRefPtr::kDisabled,
  90. PartitionOptions::BackupRefPtrZapping::kDisabled,
  91. PartitionOptions::UseConfigurablePool::kNo,
  92. }};
  93. };
  94. TEST_F(BaseAllocatorDispatcherTest, VerifyNotificationUsingPartitionAllocator) {
  95. PartitionAllocator allocator;
  96. DoBasicTest(allocator);
  97. }
  98. #endif
  99. #if BUILDFLAG(USE_ALLOCATOR_SHIM)
  100. struct AllocatorShimAllocator {
  101. void* Alloc(size_t size) { return base::allocator::UncheckedAlloc(size); }
  102. void Free(void* data) { base::allocator::UncheckedFree(data); }
  103. };
  104. #if BUILDFLAG(IS_APPLE) && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
  105. // Disable the test when running on any of Apple's OSs without PartitionAlloc
  106. // being the default allocator. In this case, all allocations are routed to
  107. // MallocImpl, which then causes the test to terminate unexpectedly.
  108. #define MAYBE_VerifyNotificationUsingAllocatorShim \
  109. DISABLED_VerifyNotificationUsingAllocatorShim
  110. #else
  111. #define MAYBE_VerifyNotificationUsingAllocatorShim \
  112. VerifyNotificationUsingAllocatorShim
  113. #endif
  114. TEST_F(BaseAllocatorDispatcherTest, MAYBE_VerifyNotificationUsingAllocatorShim) {
  115. AllocatorShimAllocator allocator;
  116. DoBasicTest(allocator);
  117. }
  118. #endif
  119. } // namespace
  120. } // namespace base::allocator::dispatcher