// Copyright 2020 The Chromium Authors // 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_features.h" #include "base/allocator/miracle_parameter.h" #include "base/base_export.h" #include "base/feature_list.h" #include "base/features.h" #include "base/metrics/field_trial_params.h" #include "base/time/time.h" #include "build/build_config.h" #include "build/chromecast_buildflags.h" #include "build/chromeos_buildflags.h" #include "partition_alloc/partition_alloc_base/time/time.h" #include "partition_alloc/partition_alloc_buildflags.h" #include "partition_alloc/partition_root.h" #include "partition_alloc/shim/allocator_shim_dispatch_to_noop_on_free.h" #include "partition_alloc/thread_cache.h" namespace base { namespace features { BASE_FEATURE(kPartitionAllocUnretainedDanglingPtr, "PartitionAllocUnretainedDanglingPtr", FEATURE_ENABLED_BY_DEFAULT); constexpr FeatureParam::Option kUnretainedDanglingPtrModeOption[] = { {UnretainedDanglingPtrMode::kCrash, "crash"}, {UnretainedDanglingPtrMode::kDumpWithoutCrashing, "dump_without_crashing"}, }; const base::FeatureParam kUnretainedDanglingPtrModeParam = { &kPartitionAllocUnretainedDanglingPtr, "mode", UnretainedDanglingPtrMode::kCrash, &kUnretainedDanglingPtrModeOption, }; BASE_FEATURE(kPartitionAllocDanglingPtr, "PartitionAllocDanglingPtr", #if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_FEATURE_FLAG) FEATURE_ENABLED_BY_DEFAULT #else FEATURE_DISABLED_BY_DEFAULT #endif ); constexpr FeatureParam::Option kDanglingPtrModeOption[] = { {DanglingPtrMode::kCrash, "crash"}, {DanglingPtrMode::kLogOnly, "log_only"}, }; const base::FeatureParam kDanglingPtrModeParam{ &kPartitionAllocDanglingPtr, "mode", DanglingPtrMode::kCrash, &kDanglingPtrModeOption, }; constexpr FeatureParam::Option kDanglingPtrTypeOption[] = { {DanglingPtrType::kAll, "all"}, {DanglingPtrType::kCrossTask, "cross_task"}, }; const base::FeatureParam kDanglingPtrTypeParam{ &kPartitionAllocDanglingPtr, "type", DanglingPtrType::kAll, &kDanglingPtrTypeOption, }; #if BUILDFLAG(USE_STARSCAN) // If enabled, PCScan is turned on by default for all partitions that don't // disable it explicitly. BASE_FEATURE(kPartitionAllocPCScan, "PartitionAllocPCScan", FEATURE_DISABLED_BY_DEFAULT); #endif // BUILDFLAG(USE_STARSCAN) #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) // If enabled, PCScan is turned on only for the browser's malloc partition. BASE_FEATURE(kPartitionAllocPCScanBrowserOnly, "PartitionAllocPCScanBrowserOnly", FEATURE_DISABLED_BY_DEFAULT); // If enabled, PCScan is turned on only for the renderer's malloc partition. BASE_FEATURE(kPartitionAllocPCScanRendererOnly, "PartitionAllocPCScanRendererOnly", FEATURE_DISABLED_BY_DEFAULT); // Use a larger maximum thread cache cacheable bucket size. BASE_FEATURE(kPartitionAllocLargeThreadCacheSize, "PartitionAllocLargeThreadCacheSize", FEATURE_ENABLED_BY_DEFAULT); MIRACLE_PARAMETER_FOR_INT( GetPartitionAllocLargeThreadCacheSizeValue, kPartitionAllocLargeThreadCacheSize, "PartitionAllocLargeThreadCacheSizeValue", ::partition_alloc::ThreadCacheLimits::kLargeSizeThreshold) MIRACLE_PARAMETER_FOR_INT( GetPartitionAllocLargeThreadCacheSizeValueForLowRAMAndroid, kPartitionAllocLargeThreadCacheSize, "PartitionAllocLargeThreadCacheSizeValueForLowRAMAndroid", ::partition_alloc::ThreadCacheLimits::kDefaultSizeThreshold) BASE_FEATURE(kPartitionAllocLargeEmptySlotSpanRing, "PartitionAllocLargeEmptySlotSpanRing", FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kPartitionAllocSchedulerLoopQuarantine, "PartitionAllocSchedulerLoopQuarantine", FEATURE_DISABLED_BY_DEFAULT); // Scheduler Loop Quarantine's capacity in bytes. const base::FeatureParam kPartitionAllocSchedulerLoopQuarantineCapacity{ &kPartitionAllocSchedulerLoopQuarantine, "PartitionAllocSchedulerLoopQuarantineCapacity", 0}; BASE_FEATURE(kPartitionAllocZappingByFreeFlags, "PartitionAllocZappingByFreeFlags", FEATURE_DISABLED_BY_DEFAULT); #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) BASE_FEATURE(kPartitionAllocBackupRefPtr, "PartitionAllocBackupRefPtr", #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) || \ (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CASTOS)) || \ BUILDFLAG(ENABLE_BACKUP_REF_PTR_FEATURE_FLAG) FEATURE_ENABLED_BY_DEFAULT #else FEATURE_DISABLED_BY_DEFAULT #endif ); constexpr FeatureParam::Option kBackupRefPtrEnabledProcessesOptions[] = { {BackupRefPtrEnabledProcesses::kBrowserOnly, "browser-only"}, {BackupRefPtrEnabledProcesses::kBrowserAndRenderer, "browser-and-renderer"}, {BackupRefPtrEnabledProcesses::kNonRenderer, "non-renderer"}, {BackupRefPtrEnabledProcesses::kAllProcesses, "all-processes"}}; const base::FeatureParam kBackupRefPtrEnabledProcessesParam{ &kPartitionAllocBackupRefPtr, "enabled-processes", BackupRefPtrEnabledProcesses::kNonRenderer, &kBackupRefPtrEnabledProcessesOptions}; constexpr FeatureParam::Option kBackupRefPtrModeOptions[] = { {BackupRefPtrMode::kDisabled, "disabled"}, {BackupRefPtrMode::kEnabled, "enabled"}, {BackupRefPtrMode::kEnabled, "enabled-in-same-slot-mode"}, }; const base::FeatureParam kBackupRefPtrModeParam{ &kPartitionAllocBackupRefPtr, "brp-mode", BackupRefPtrMode::kEnabled, &kBackupRefPtrModeOptions}; BASE_FEATURE(kPartitionAllocMemoryTagging, "PartitionAllocMemoryTagging", #if BUILDFLAG(USE_FULL_MTE) FEATURE_ENABLED_BY_DEFAULT #else FEATURE_DISABLED_BY_DEFAULT #endif ); constexpr FeatureParam::Option kMemtagModeOptions[] = { {MemtagMode::kSync, "sync"}, {MemtagMode::kAsync, "async"}}; const base::FeatureParam kMemtagModeParam{ &kPartitionAllocMemoryTagging, "memtag-mode", #if BUILDFLAG(USE_FULL_MTE) MemtagMode::kSync, #else MemtagMode::kAsync, #endif &kMemtagModeOptions}; constexpr FeatureParam::Option kMemoryTaggingEnabledProcessesOptions[] = { {MemoryTaggingEnabledProcesses::kBrowserOnly, "browser-only"}, {MemoryTaggingEnabledProcesses::kNonRenderer, "non-renderer"}, {MemoryTaggingEnabledProcesses::kAllProcesses, "all-processes"}}; const base::FeatureParam kMemoryTaggingEnabledProcessesParam{ &kPartitionAllocMemoryTagging, "enabled-processes", #if BUILDFLAG(USE_FULL_MTE) MemoryTaggingEnabledProcesses::kAllProcesses, #else MemoryTaggingEnabledProcesses::kBrowserOnly, #endif &kMemoryTaggingEnabledProcessesOptions}; BASE_FEATURE(kKillPartitionAllocMemoryTagging, "KillPartitionAllocMemoryTagging", FEATURE_DISABLED_BY_DEFAULT); BASE_EXPORT BASE_DECLARE_FEATURE(kPartitionAllocPermissiveMte); BASE_FEATURE(kPartitionAllocPermissiveMte, "PartitionAllocPermissiveMte", #if BUILDFLAG(USE_FULL_MTE) // We want to actually crash if USE_FULL_MTE is enabled. FEATURE_DISABLED_BY_DEFAULT #else FEATURE_ENABLED_BY_DEFAULT #endif ); const base::FeatureParam kBackupRefPtrAsanEnableDereferenceCheckParam{ &kPartitionAllocBackupRefPtr, "asan-enable-dereference-check", true}; const base::FeatureParam kBackupRefPtrAsanEnableExtractionCheckParam{ &kPartitionAllocBackupRefPtr, "asan-enable-extraction-check", false}; // Not much noise at the moment to enable by default. const base::FeatureParam kBackupRefPtrAsanEnableInstantiationCheckParam{ &kPartitionAllocBackupRefPtr, "asan-enable-instantiation-check", true}; // If enabled, switches the bucket distribution to a denser one. // // We enable this by default everywhere except for 32-bit Android, since we saw // regressions there. BASE_FEATURE(kPartitionAllocUseDenserDistribution, "PartitionAllocUseDenserDistribution", #if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_32_BITS) FEATURE_DISABLED_BY_DEFAULT #else FEATURE_ENABLED_BY_DEFAULT #endif // BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_32_BITS) ); const base::FeatureParam::Option kPartitionAllocBucketDistributionOption[] = { {BucketDistributionMode::kDefault, "default"}, {BucketDistributionMode::kDenser, "denser"}, }; const base::FeatureParam kPartitionAllocBucketDistributionParam { &kPartitionAllocUseDenserDistribution, "mode", #if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_32_BITS) BucketDistributionMode::kDefault, #else BucketDistributionMode::kDenser, #endif // BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_32_BITS) &kPartitionAllocBucketDistributionOption }; BASE_FEATURE(kPartitionAllocMemoryReclaimer, "PartitionAllocMemoryReclaimer", FEATURE_ENABLED_BY_DEFAULT); const base::FeatureParam kPartitionAllocMemoryReclaimerInterval = { &kPartitionAllocMemoryReclaimer, "interval", TimeDelta(), // Defaults to zero. }; // Configures whether we set a lower limit for renderers that do not have a main // frame, similar to the limit that is already done for backgrounded renderers. BASE_FEATURE(kLowerPAMemoryLimitForNonMainRenderers, "LowerPAMemoryLimitForNonMainRenderers", FEATURE_DISABLED_BY_DEFAULT); // If enabled, switches PCScan scheduling to a mutator-aware scheduler. Does not // affect whether PCScan is enabled itself. BASE_FEATURE(kPartitionAllocPCScanMUAwareScheduler, "PartitionAllocPCScanMUAwareScheduler", FEATURE_ENABLED_BY_DEFAULT); // If enabled, PCScan frees unconditionally all quarantined objects. // This is a performance testing feature. BASE_FEATURE(kPartitionAllocPCScanImmediateFreeing, "PartitionAllocPCScanImmediateFreeing", FEATURE_DISABLED_BY_DEFAULT); // If enabled, PCScan clears eagerly (synchronously) on free(). BASE_FEATURE(kPartitionAllocPCScanEagerClearing, "PartitionAllocPCScanEagerClearing", FEATURE_DISABLED_BY_DEFAULT); // In addition to heap, scan also the stack of the current mutator. BASE_FEATURE(kPartitionAllocPCScanStackScanning, "PartitionAllocPCScanStackScanning", #if BUILDFLAG(STACK_SCAN_SUPPORTED) FEATURE_ENABLED_BY_DEFAULT #else FEATURE_DISABLED_BY_DEFAULT #endif // BUILDFLAG(STACK_SCAN_SUPPORTED) ); BASE_FEATURE(kPartitionAllocDCScan, "PartitionAllocDCScan", FEATURE_DISABLED_BY_DEFAULT); // Whether to straighten free lists for larger slot spans in PurgeMemory() -> // ... -> PartitionPurgeSlotSpan(). BASE_FEATURE(kPartitionAllocStraightenLargerSlotSpanFreeLists, "PartitionAllocStraightenLargerSlotSpanFreeLists", FEATURE_ENABLED_BY_DEFAULT); const base::FeatureParam< partition_alloc::StraightenLargerSlotSpanFreeListsMode>::Option kPartitionAllocStraightenLargerSlotSpanFreeListsModeOption[] = { {partition_alloc::StraightenLargerSlotSpanFreeListsMode:: kOnlyWhenUnprovisioning, "only-when-unprovisioning"}, {partition_alloc::StraightenLargerSlotSpanFreeListsMode::kAlways, "always"}, }; const base::FeatureParam kPartitionAllocStraightenLargerSlotSpanFreeListsMode = { &kPartitionAllocStraightenLargerSlotSpanFreeLists, "mode", partition_alloc::StraightenLargerSlotSpanFreeListsMode:: kOnlyWhenUnprovisioning, &kPartitionAllocStraightenLargerSlotSpanFreeListsModeOption, }; // Whether to sort free lists for smaller slot spans in PurgeMemory(). BASE_FEATURE(kPartitionAllocSortSmallerSlotSpanFreeLists, "PartitionAllocSortSmallerSlotSpanFreeLists", FEATURE_ENABLED_BY_DEFAULT); // Whether to sort the active slot spans in PurgeMemory(). BASE_FEATURE(kPartitionAllocSortActiveSlotSpans, "PartitionAllocSortActiveSlotSpans", FEATURE_DISABLED_BY_DEFAULT); #if BUILDFLAG(IS_WIN) // Whether to retry allocations when commit fails. BASE_FEATURE(kPageAllocatorRetryOnCommitFailure, "PageAllocatorRetryOnCommitFailure", FEATURE_DISABLED_BY_DEFAULT); #endif #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) // A parameter to exclude or not exclude PartitionAllocSupport from // PartialLowModeOnMidRangeDevices. This is used to see how it affects // renderer performances, e.g. blink_perf.parser benchmark. // The feature: kPartialLowEndModeOnMidRangeDevices is defined in // //base/features.cc. Since the following feature param is related to // PartitionAlloc, define the param here. const FeatureParam kPartialLowEndModeExcludePartitionAllocSupport{ &kPartialLowEndModeOnMidRangeDevices, "exclude-partition-alloc-support", false}; #endif BASE_FEATURE(kEnableConfigurableThreadCacheMultiplier, "EnableConfigurableThreadCacheMultiplier", base::FEATURE_DISABLED_BY_DEFAULT); MIRACLE_PARAMETER_FOR_DOUBLE(GetThreadCacheMultiplier, kEnableConfigurableThreadCacheMultiplier, "ThreadCacheMultiplier", 2.) MIRACLE_PARAMETER_FOR_DOUBLE(GetThreadCacheMultiplierForAndroid, kEnableConfigurableThreadCacheMultiplier, "ThreadCacheMultiplierForAndroid", 1.) constexpr partition_alloc::internal::base::TimeDelta ToPartitionAllocTimeDelta( base::TimeDelta time_delta) { return partition_alloc::internal::base::Microseconds( time_delta.InMicroseconds()); } constexpr base::TimeDelta FromPartitionAllocTimeDelta( partition_alloc::internal::base::TimeDelta time_delta) { return base::Microseconds(time_delta.InMicroseconds()); } BASE_FEATURE(kEnableConfigurableThreadCachePurgeInterval, "EnableConfigurableThreadCachePurgeInterval", base::FEATURE_DISABLED_BY_DEFAULT); MIRACLE_PARAMETER_FOR_TIME_DELTA( GetThreadCacheMinPurgeIntervalValue, kEnableConfigurableThreadCachePurgeInterval, "ThreadCacheMinPurgeInterval", FromPartitionAllocTimeDelta(partition_alloc::kMinPurgeInterval)) MIRACLE_PARAMETER_FOR_TIME_DELTA( GetThreadCacheMaxPurgeIntervalValue, kEnableConfigurableThreadCachePurgeInterval, "ThreadCacheMaxPurgeInterval", FromPartitionAllocTimeDelta(partition_alloc::kMaxPurgeInterval)) MIRACLE_PARAMETER_FOR_TIME_DELTA( GetThreadCacheDefaultPurgeIntervalValue, kEnableConfigurableThreadCachePurgeInterval, "ThreadCacheDefaultPurgeInterval", FromPartitionAllocTimeDelta(partition_alloc::kDefaultPurgeInterval)) const partition_alloc::internal::base::TimeDelta GetThreadCacheMinPurgeInterval() { return ToPartitionAllocTimeDelta(GetThreadCacheMinPurgeIntervalValue()); } const partition_alloc::internal::base::TimeDelta GetThreadCacheMaxPurgeInterval() { return ToPartitionAllocTimeDelta(GetThreadCacheMaxPurgeIntervalValue()); } const partition_alloc::internal::base::TimeDelta GetThreadCacheDefaultPurgeInterval() { return ToPartitionAllocTimeDelta(GetThreadCacheDefaultPurgeIntervalValue()); } BASE_FEATURE(kEnableConfigurableThreadCacheMinCachedMemoryForPurging, "EnableConfigurableThreadCacheMinCachedMemoryForPurging", base::FEATURE_DISABLED_BY_DEFAULT); MIRACLE_PARAMETER_FOR_INT( GetThreadCacheMinCachedMemoryForPurgingBytes, kEnableConfigurableThreadCacheMinCachedMemoryForPurging, "ThreadCacheMinCachedMemoryForPurgingBytes", partition_alloc::kMinCachedMemoryForPurgingBytes) // An apparent quarantine leak in the buffer partition unacceptably // bloats memory when MiraclePtr is enabled in the renderer process. // We believe we have found and patched the leak, but out of an // abundance of caution, we provide this toggle that allows us to // wholly disable MiraclePtr in the buffer partition, if necessary. // // TODO(crbug.com/1444624): this is unneeded once // MiraclePtr-for-Renderer launches. BASE_FEATURE(kPartitionAllocDisableBRPInBufferPartition, "PartitionAllocDisableBRPInBufferPartition", FEATURE_DISABLED_BY_DEFAULT); #if BUILDFLAG(USE_FREELIST_POOL_OFFSETS) BASE_FEATURE(kUsePoolOffsetFreelists, "PartitionAllocUsePoolOffsetFreelists", base::FEATURE_DISABLED_BY_DEFAULT); #endif BASE_FEATURE(kPartitionAllocMakeFreeNoOpOnShutdown, "PartitionAllocMakeFreeNoOpOnShutdown", FEATURE_DISABLED_BY_DEFAULT); constexpr FeatureParam::Option kPartitionAllocMakeFreeNoOpOnShutdownOptions[] = { { WhenFreeBecomesNoOp::kBeforeShutDownThreads, "before-shutdown-threads", }, { WhenFreeBecomesNoOp::kInShutDownThreads, "in-shutdown-threads", }, { WhenFreeBecomesNoOp::kAfterShutDownThreads, "after-shutdown-threads", }, }; const base::FeatureParam kPartitionAllocMakeFreeNoOpOnShutdownParam{ &kPartitionAllocMakeFreeNoOpOnShutdown, "callsite", WhenFreeBecomesNoOp::kBeforeShutDownThreads, &kPartitionAllocMakeFreeNoOpOnShutdownOptions}; void MakeFreeNoOp(WhenFreeBecomesNoOp callsite) { CHECK(base::FeatureList::GetInstance()); // Ignoring `free()` during Shutdown would allow developers to introduce new // dangling pointers. So we want to avoid ignoring free when it is enabled. // Note: For now, the DanglingPointerDetector is only enabled on 5 bots, and // on linux non-official configuration. // TODO(b/40802063): Reconsider this decision after the experiment. #if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) if (base::FeatureList::IsEnabled(features::kPartitionAllocDanglingPtr)) { return; } #endif // BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) #if BUILDFLAG(USE_ALLOCATOR_SHIM) if (base::FeatureList::IsEnabled(kPartitionAllocMakeFreeNoOpOnShutdown) && kPartitionAllocMakeFreeNoOpOnShutdownParam.Get() == callsite) { allocator_shim::InsertNoOpOnFreeAllocatorShimOnShutDown(); } #endif // BUILDFLAG(USE_ALLOCATOR_SHIM) } BASE_FEATURE(kPartitionAllocAdjustSizeWhenInForeground, "PartitionAllocAdjustSizeWhenInForeground", base::FEATURE_DISABLED_BY_DEFAULT); } // namespace features } // namespace base