partition_alloc_support_unittest.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. #include "base/allocator/partition_alloc_support.h"
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/allocator/buildflags.h"
  9. #include "base/allocator/partition_alloc_features.h"
  10. #include "base/allocator/partition_allocator/dangling_raw_ptr_checks.h"
  11. #include "base/allocator/partition_allocator/partition_alloc_config.h"
  12. #include "base/feature_list.h"
  13. #include "base/test/scoped_feature_list.h"
  14. #include "build/build_config.h"
  15. #include "testing/gmock/include/gmock/gmock.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. namespace base {
  18. namespace allocator {
  19. using testing::AllOf;
  20. using testing::HasSubstr;
  21. #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
  22. TEST(PartitionAllocSupportTest, ProposeSyntheticFinchTrials_BRPAndPCScan) {
  23. for (bool pcscan_enabled : {false, true}) {
  24. test::ScopedFeatureList pcscan_scope;
  25. std::vector<Feature> empty_list = {};
  26. std::vector<Feature> pcscan_list = {
  27. features::kPartitionAllocPCScanBrowserOnly};
  28. pcscan_scope.InitWithFeatures(pcscan_enabled ? pcscan_list : empty_list,
  29. pcscan_enabled ? empty_list : pcscan_list);
  30. #if !defined(PA_ALLOW_PCSCAN)
  31. pcscan_enabled = false;
  32. #endif
  33. std::string brp_expectation;
  34. std::string pcscan_expectation;
  35. {
  36. test::ScopedFeatureList brp_scope;
  37. brp_scope.InitWithFeatures({}, {features::kPartitionAllocBackupRefPtr});
  38. brp_expectation = "Unavailable";
  39. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  40. brp_expectation = pcscan_enabled ? "Ignore_PCScanIsOn" : "Ignore_NoGroup";
  41. #endif
  42. pcscan_expectation = "Unavailable";
  43. #if defined(PA_ALLOW_PCSCAN)
  44. pcscan_expectation = pcscan_enabled ? "Enabled" : "Disabled";
  45. #endif
  46. auto trials = ProposeSyntheticFinchTrials();
  47. auto group_iter = trials.find("BackupRefPtr_Effective");
  48. EXPECT_NE(group_iter, trials.end());
  49. EXPECT_EQ(group_iter->second, brp_expectation);
  50. group_iter = trials.find("PCScan_Effective");
  51. EXPECT_NE(group_iter, trials.end());
  52. EXPECT_EQ(group_iter->second, pcscan_expectation);
  53. group_iter = trials.find("PCScan_Effective_Fallback");
  54. EXPECT_NE(group_iter, trials.end());
  55. EXPECT_EQ(group_iter->second, pcscan_expectation);
  56. }
  57. {
  58. test::ScopedFeatureList brp_scope;
  59. brp_scope.InitAndEnableFeatureWithParameters(
  60. features::kPartitionAllocBackupRefPtr, {});
  61. brp_expectation = "Unavailable";
  62. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  63. brp_expectation = pcscan_enabled ? "Ignore_PCScanIsOn"
  64. #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
  65. : "EnabledPrevSlot_BrowserOnly";
  66. #else
  67. : "EnabledBeforeAlloc_BrowserOnly";
  68. #endif // BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
  69. #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
  70. pcscan_expectation = "Unavailable";
  71. #if defined(PA_ALLOW_PCSCAN)
  72. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  73. pcscan_expectation = "Ignore_BRPIsOn";
  74. #else
  75. pcscan_expectation = pcscan_enabled ? "Enabled" : "Disabled";
  76. #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
  77. #endif // defined(PA_ALLOW_PCSCAN)
  78. auto trials = ProposeSyntheticFinchTrials();
  79. auto group_iter = trials.find("BackupRefPtr_Effective");
  80. EXPECT_NE(group_iter, trials.end());
  81. EXPECT_EQ(group_iter->second, brp_expectation);
  82. group_iter = trials.find("PCScan_Effective");
  83. EXPECT_NE(group_iter, trials.end());
  84. EXPECT_EQ(group_iter->second, pcscan_expectation);
  85. group_iter = trials.find("PCScan_Effective_Fallback");
  86. EXPECT_NE(group_iter, trials.end());
  87. EXPECT_EQ(group_iter->second, pcscan_expectation);
  88. }
  89. const std::string kEnabledMode =
  90. #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
  91. "PrevSlot_";
  92. #else
  93. "BeforeAlloc_";
  94. #endif
  95. const std::vector<std::pair<std::string, std::string>> kModes = {
  96. {"disabled", "Disabled"},
  97. {"enabled", "Enabled" + kEnabledMode},
  98. {"disabled-but-2-way-split", "DisabledBut2WaySplit_"},
  99. {"disabled-but-3-way-split", "DisabledBut3WaySplit_"}};
  100. const std::vector<std::pair<std::string, std::string>> kProcesses = {
  101. {"browser-only", "BrowserOnly"},
  102. {"browser-and-renderer", "BrowserAndRenderer"},
  103. {"non-renderer", "NonRenderer"},
  104. {"all-processes", "AllProcesses"}};
  105. for (auto mode : kModes) {
  106. for (auto process_set : kProcesses) {
  107. test::ScopedFeatureList brp_scope;
  108. brp_scope.InitAndEnableFeatureWithParameters(
  109. features::kPartitionAllocBackupRefPtr,
  110. {{"brp-mode", mode.first},
  111. {"enabled-processes", process_set.first}});
  112. [[maybe_unused]] bool brp_truly_enabled = false;
  113. [[maybe_unused]] bool brp_nondefault_behavior = false;
  114. brp_expectation = "Unavailable";
  115. #if BUILDFLAG(USE_BACKUP_REF_PTR)
  116. brp_expectation = pcscan_enabled ? "Ignore_PCScanIsOn" : mode.second;
  117. brp_truly_enabled = (mode.first == "enabled");
  118. brp_nondefault_behavior = (mode.first != "disabled");
  119. #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
  120. if (brp_expectation[brp_expectation.length() - 1] == '_') {
  121. brp_expectation += process_set.second;
  122. }
  123. pcscan_expectation = "Unavailable";
  124. std::string pcscan_expectation_fallback = "Unavailable";
  125. #if defined(PA_ALLOW_PCSCAN)
  126. pcscan_expectation = brp_truly_enabled
  127. ? "Ignore_BRPIsOn"
  128. : (pcscan_enabled ? "Enabled" : "Disabled");
  129. pcscan_expectation_fallback =
  130. brp_nondefault_behavior ? "Ignore_BRPIsOn"
  131. : (pcscan_enabled ? "Enabled" : "Disabled");
  132. #endif // defined(PA_ALLOW_PCSCAN)
  133. auto trials = ProposeSyntheticFinchTrials();
  134. auto group_iter = trials.find("BackupRefPtr_Effective");
  135. EXPECT_NE(group_iter, trials.end());
  136. EXPECT_EQ(group_iter->second, brp_expectation);
  137. group_iter = trials.find("PCScan_Effective");
  138. EXPECT_NE(group_iter, trials.end());
  139. EXPECT_EQ(group_iter->second, pcscan_expectation);
  140. group_iter = trials.find("PCScan_Effective_Fallback");
  141. EXPECT_NE(group_iter, trials.end());
  142. EXPECT_EQ(group_iter->second, pcscan_expectation_fallback);
  143. }
  144. }
  145. }
  146. }
  147. #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
  148. // - Death tests misbehave on Android, http://crbug.com/643760.
  149. #if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) && !BUILDFLAG(IS_ANDROID) && \
  150. defined(GTEST_HAS_DEATH_TEST)
  151. namespace {
  152. // Install dangling raw_ptr handler and restore them when going out of scope.
  153. class ScopedInstallDanglingRawPtrChecks {
  154. public:
  155. ScopedInstallDanglingRawPtrChecks() {
  156. enabled_feature_list_.InitWithFeaturesAndParameters(
  157. {{features::kPartitionAllocDanglingPtr, {{"mode", "crash"}}}},
  158. {/* disabled_features */});
  159. old_detected_fn_ = partition_alloc::GetDanglingRawPtrDetectedFn();
  160. old_dereferenced_fn_ = partition_alloc::GetDanglingRawPtrReleasedFn();
  161. InstallDanglingRawPtrChecks();
  162. }
  163. ~ScopedInstallDanglingRawPtrChecks() {
  164. partition_alloc::SetDanglingRawPtrDetectedFn(old_detected_fn_);
  165. partition_alloc::SetDanglingRawPtrReleasedFn(old_dereferenced_fn_);
  166. }
  167. private:
  168. test::ScopedFeatureList enabled_feature_list_;
  169. partition_alloc::DanglingRawPtrDetectedFn* old_detected_fn_;
  170. partition_alloc::DanglingRawPtrReleasedFn* old_dereferenced_fn_;
  171. };
  172. } // namespace
  173. TEST(PartitionAllocDanglingPtrChecks, Basic) {
  174. ScopedInstallDanglingRawPtrChecks scoped_install_dangling_checks;
  175. partition_alloc::GetDanglingRawPtrDetectedFn()(42);
  176. EXPECT_DEATH(
  177. partition_alloc::GetDanglingRawPtrReleasedFn()(42),
  178. AllOf(HasSubstr("Detected dangling raw_ptr with id=0x000000000000002a:"),
  179. HasSubstr("The memory was freed at:"),
  180. HasSubstr("The dangling raw_ptr was released at:")));
  181. }
  182. // The StackTrace buffer might run out of storage and not record where the
  183. // memory was freed. Anyway, it must still report the error.
  184. TEST(PartitionAllocDanglingPtrChecks, FreeNotRecorded) {
  185. ScopedInstallDanglingRawPtrChecks scoped_install_dangling_checks;
  186. EXPECT_DEATH(
  187. partition_alloc::GetDanglingRawPtrReleasedFn()(42),
  188. AllOf(HasSubstr("Detected dangling raw_ptr with id=0x000000000000002a:"),
  189. HasSubstr("It was not recorded where the memory was freed."),
  190. HasSubstr("The dangling raw_ptr was released at:")));
  191. }
  192. TEST(PartitionAllocDanglingPtrChecks, DoubleDetection) {
  193. ScopedInstallDanglingRawPtrChecks scoped_install_dangling_checks;
  194. partition_alloc::GetDanglingRawPtrDetectedFn()(42);
  195. #if DCHECK_IS_ON()
  196. EXPECT_DEATH(partition_alloc::GetDanglingRawPtrDetectedFn()(42),
  197. AllOf(HasSubstr("Check failed: !entry || entry->id != id")));
  198. #else
  199. partition_alloc::GetDanglingRawPtrDetectedFn()(42);
  200. #endif
  201. }
  202. #endif
  203. } // namespace allocator
  204. } // namespace base