123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/allocator/partition_alloc_support.h"
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/allocator/buildflags.h"
- #include "base/allocator/partition_alloc_features.h"
- #include "base/allocator/partition_allocator/dangling_raw_ptr_checks.h"
- #include "base/allocator/partition_allocator/partition_alloc_config.h"
- #include "base/feature_list.h"
- #include "base/test/scoped_feature_list.h"
- #include "build/build_config.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace base {
- namespace allocator {
- using testing::AllOf;
- using testing::HasSubstr;
- #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
- TEST(PartitionAllocSupportTest, ProposeSyntheticFinchTrials_BRPAndPCScan) {
- for (bool pcscan_enabled : {false, true}) {
- test::ScopedFeatureList pcscan_scope;
- std::vector<Feature> empty_list = {};
- std::vector<Feature> pcscan_list = {
- features::kPartitionAllocPCScanBrowserOnly};
- pcscan_scope.InitWithFeatures(pcscan_enabled ? pcscan_list : empty_list,
- pcscan_enabled ? empty_list : pcscan_list);
- #if !defined(PA_ALLOW_PCSCAN)
- pcscan_enabled = false;
- #endif
- std::string brp_expectation;
- std::string pcscan_expectation;
- {
- test::ScopedFeatureList brp_scope;
- brp_scope.InitWithFeatures({}, {features::kPartitionAllocBackupRefPtr});
- brp_expectation = "Unavailable";
- #if BUILDFLAG(USE_BACKUP_REF_PTR)
- brp_expectation = pcscan_enabled ? "Ignore_PCScanIsOn" : "Ignore_NoGroup";
- #endif
- pcscan_expectation = "Unavailable";
- #if defined(PA_ALLOW_PCSCAN)
- pcscan_expectation = pcscan_enabled ? "Enabled" : "Disabled";
- #endif
- auto trials = ProposeSyntheticFinchTrials();
- auto group_iter = trials.find("BackupRefPtr_Effective");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, brp_expectation);
- group_iter = trials.find("PCScan_Effective");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, pcscan_expectation);
- group_iter = trials.find("PCScan_Effective_Fallback");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, pcscan_expectation);
- }
- {
- test::ScopedFeatureList brp_scope;
- brp_scope.InitAndEnableFeatureWithParameters(
- features::kPartitionAllocBackupRefPtr, {});
- brp_expectation = "Unavailable";
- #if BUILDFLAG(USE_BACKUP_REF_PTR)
- brp_expectation = pcscan_enabled ? "Ignore_PCScanIsOn"
- #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
- : "EnabledPrevSlot_BrowserOnly";
- #else
- : "EnabledBeforeAlloc_BrowserOnly";
- #endif // BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
- #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
- pcscan_expectation = "Unavailable";
- #if defined(PA_ALLOW_PCSCAN)
- #if BUILDFLAG(USE_BACKUP_REF_PTR)
- pcscan_expectation = "Ignore_BRPIsOn";
- #else
- pcscan_expectation = pcscan_enabled ? "Enabled" : "Disabled";
- #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
- #endif // defined(PA_ALLOW_PCSCAN)
- auto trials = ProposeSyntheticFinchTrials();
- auto group_iter = trials.find("BackupRefPtr_Effective");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, brp_expectation);
- group_iter = trials.find("PCScan_Effective");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, pcscan_expectation);
- group_iter = trials.find("PCScan_Effective_Fallback");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, pcscan_expectation);
- }
- const std::string kEnabledMode =
- #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
- "PrevSlot_";
- #else
- "BeforeAlloc_";
- #endif
- const std::vector<std::pair<std::string, std::string>> kModes = {
- {"disabled", "Disabled"},
- {"enabled", "Enabled" + kEnabledMode},
- {"disabled-but-2-way-split", "DisabledBut2WaySplit_"},
- {"disabled-but-3-way-split", "DisabledBut3WaySplit_"}};
- const std::vector<std::pair<std::string, std::string>> kProcesses = {
- {"browser-only", "BrowserOnly"},
- {"browser-and-renderer", "BrowserAndRenderer"},
- {"non-renderer", "NonRenderer"},
- {"all-processes", "AllProcesses"}};
- for (auto mode : kModes) {
- for (auto process_set : kProcesses) {
- test::ScopedFeatureList brp_scope;
- brp_scope.InitAndEnableFeatureWithParameters(
- features::kPartitionAllocBackupRefPtr,
- {{"brp-mode", mode.first},
- {"enabled-processes", process_set.first}});
- [[maybe_unused]] bool brp_truly_enabled = false;
- [[maybe_unused]] bool brp_nondefault_behavior = false;
- brp_expectation = "Unavailable";
- #if BUILDFLAG(USE_BACKUP_REF_PTR)
- brp_expectation = pcscan_enabled ? "Ignore_PCScanIsOn" : mode.second;
- brp_truly_enabled = (mode.first == "enabled");
- brp_nondefault_behavior = (mode.first != "disabled");
- #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
- if (brp_expectation[brp_expectation.length() - 1] == '_') {
- brp_expectation += process_set.second;
- }
- pcscan_expectation = "Unavailable";
- std::string pcscan_expectation_fallback = "Unavailable";
- #if defined(PA_ALLOW_PCSCAN)
- pcscan_expectation = brp_truly_enabled
- ? "Ignore_BRPIsOn"
- : (pcscan_enabled ? "Enabled" : "Disabled");
- pcscan_expectation_fallback =
- brp_nondefault_behavior ? "Ignore_BRPIsOn"
- : (pcscan_enabled ? "Enabled" : "Disabled");
- #endif // defined(PA_ALLOW_PCSCAN)
- auto trials = ProposeSyntheticFinchTrials();
- auto group_iter = trials.find("BackupRefPtr_Effective");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, brp_expectation);
- group_iter = trials.find("PCScan_Effective");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, pcscan_expectation);
- group_iter = trials.find("PCScan_Effective_Fallback");
- EXPECT_NE(group_iter, trials.end());
- EXPECT_EQ(group_iter->second, pcscan_expectation_fallback);
- }
- }
- }
- }
- #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
- // - Death tests misbehave on Android, http://crbug.com/643760.
- #if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) && !BUILDFLAG(IS_ANDROID) && \
- defined(GTEST_HAS_DEATH_TEST)
- namespace {
- // Install dangling raw_ptr handler and restore them when going out of scope.
- class ScopedInstallDanglingRawPtrChecks {
- public:
- ScopedInstallDanglingRawPtrChecks() {
- enabled_feature_list_.InitWithFeaturesAndParameters(
- {{features::kPartitionAllocDanglingPtr, {{"mode", "crash"}}}},
- {/* disabled_features */});
- old_detected_fn_ = partition_alloc::GetDanglingRawPtrDetectedFn();
- old_dereferenced_fn_ = partition_alloc::GetDanglingRawPtrReleasedFn();
- InstallDanglingRawPtrChecks();
- }
- ~ScopedInstallDanglingRawPtrChecks() {
- partition_alloc::SetDanglingRawPtrDetectedFn(old_detected_fn_);
- partition_alloc::SetDanglingRawPtrReleasedFn(old_dereferenced_fn_);
- }
- private:
- test::ScopedFeatureList enabled_feature_list_;
- partition_alloc::DanglingRawPtrDetectedFn* old_detected_fn_;
- partition_alloc::DanglingRawPtrReleasedFn* old_dereferenced_fn_;
- };
- } // namespace
- TEST(PartitionAllocDanglingPtrChecks, Basic) {
- ScopedInstallDanglingRawPtrChecks scoped_install_dangling_checks;
- partition_alloc::GetDanglingRawPtrDetectedFn()(42);
- EXPECT_DEATH(
- partition_alloc::GetDanglingRawPtrReleasedFn()(42),
- AllOf(HasSubstr("Detected dangling raw_ptr with id=0x000000000000002a:"),
- HasSubstr("The memory was freed at:"),
- HasSubstr("The dangling raw_ptr was released at:")));
- }
- // The StackTrace buffer might run out of storage and not record where the
- // memory was freed. Anyway, it must still report the error.
- TEST(PartitionAllocDanglingPtrChecks, FreeNotRecorded) {
- ScopedInstallDanglingRawPtrChecks scoped_install_dangling_checks;
- EXPECT_DEATH(
- partition_alloc::GetDanglingRawPtrReleasedFn()(42),
- AllOf(HasSubstr("Detected dangling raw_ptr with id=0x000000000000002a:"),
- HasSubstr("It was not recorded where the memory was freed."),
- HasSubstr("The dangling raw_ptr was released at:")));
- }
- TEST(PartitionAllocDanglingPtrChecks, DoubleDetection) {
- ScopedInstallDanglingRawPtrChecks scoped_install_dangling_checks;
- partition_alloc::GetDanglingRawPtrDetectedFn()(42);
- #if DCHECK_IS_ON()
- EXPECT_DEATH(partition_alloc::GetDanglingRawPtrDetectedFn()(42),
- AllOf(HasSubstr("Check failed: !entry || entry->id != id")));
- #else
- partition_alloc::GetDanglingRawPtrDetectedFn()(42);
- #endif
- }
- #endif
- } // namespace allocator
- } // namespace base
|