// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_MEMORY_SAFETY_CHECKS_H_ #define BASE_MEMORY_SAFETY_CHECKS_H_ #include <new> #include <type_traits> #include "base/compiler_specific.h" #include "base/dcheck_is_on.h" #include "partition_alloc/buildflags.h" #include "partition_alloc/partition_alloc_constants.h" #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #include "partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h" #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) // This header defines `ADVANCED_MEMORY_SAFETY_CHECKS()` macro. // They can be used to specify a class/struct that is targeted to perform // additional CHECKS across variety of memory safety mechanisms such as // PartitionAllocator. // ``` // class Foo { // ADVANCED_MEMORY_SAFETY_CHECKS(); // } // ``` // Checks here are disabled by default because of their performance cost. // Currently, the macro is managed by the memory safety team internally and // you should not add / remove it manually. // // Additional checks here are categorized into either one of enum // `MemorySafetyCheck`. Some of them are too costly and disabled even for // `ADVANCED_MEMORY_SAFETY_CHECKS()` annotated types. These checks can be // enabled by passing optional arguments to the macro. // ``` // class Foo { // ADVANCED_MEMORY_SAFETY_CHECKS( // /*enable=*/ kFoo | kBar); // } // ``` // It is also possible to disable default checks for annotated types. // ``` // class Foo { // ADVANCED_MEMORY_SAFETY_CHECKS( // /*enable=*/ kFoo, // /*disable=*/ kBaz); // } // ``` // We cannot hide things behind anonymous namespace because they are referenced // via macro, which can be defined anywhere. // To avoid tainting ::base namespace, define things inside this namespace. namespace base::internal { enum class MemorySafetyCheck : uint32_t { … }; constexpr MemorySafetyCheck operator|(MemorySafetyCheck a, MemorySafetyCheck b) { … } constexpr MemorySafetyCheck operator&(MemorySafetyCheck a, MemorySafetyCheck b) { … } constexpr MemorySafetyCheck operator~(MemorySafetyCheck a) { … } // Set of checks for ADVANCED_MEMORY_SAFETY_CHECKS() annotated objects. constexpr auto kAdvancedMemorySafetyChecks = …; // Define type traits to determine type |T|'s memory safety check status. namespace { // Allocator type traits. constexpr bool ShouldUsePartitionAlloc(MemorySafetyCheck checks) { … } // Returns |partition_alloc::AllocFlags| corresponding to |checks|. constexpr partition_alloc::AllocFlags GetAllocFlags(MemorySafetyCheck checks) { … } // Returns |partition_alloc::FreeFlags| corresponding to |checks|. constexpr partition_alloc::FreeFlags GetFreeFlags(MemorySafetyCheck checks) { … } } // namespace // Public utility type traits. get_memory_safety_checks; is_memory_safety_checked; // Allocator functions. #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) ALWAYS_INLINE partition_alloc::PartitionRoot* GetPartitionRootForMemorySafetyCheckedAllocation() { … } #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) template <MemorySafetyCheck checks> NOINLINE void* HandleMemorySafetyCheckedOperatorNew(std::size_t count) { … } template <MemorySafetyCheck checks> NOINLINE void* HandleMemorySafetyCheckedOperatorNew( std::size_t count, std::align_val_t alignment) { … } template <MemorySafetyCheck checks> NOINLINE void HandleMemorySafetyCheckedOperatorDelete(void* ptr) { … } template <MemorySafetyCheck checks> NOINLINE void HandleMemorySafetyCheckedOperatorDelete( void* ptr, std::align_val_t alignment) { … } } // namespace base::internal // Macros to annotate class/struct's default memory safety check. // ADVANCED_MEMORY_SAFETY_CHECKS(): Enable Check |kAdvancedChecks| for this // object. // // Note that if you use this macro at the top of struct declaration, the // declaration context would be left as |private|. Please switch it back to // |public| manually if needed. // // struct ObjectWithAdvancedChecks { // ADVANCED_MEMORY_SAFETY_CHECKS(); // public: // int public_field; // }; #define MEMORY_SAFETY_CHECKS_INTERNAL(SPECIFIER, DEFAULT_CHECKS, \ ENABLED_CHECKS, DISABLED_CHECKS, ...) … #if DCHECK_IS_ON() // Specify NOINLINE to display the operator on a stack trace. // When 2 args provided, these two are passed to `ENABLED_CHECKS` and // `DISABLED_CHECKS`. A couple of `MemorySafetyCheck::kNone` is ignored. // When 1 arg provided, the one is passed to `ENABLED_CHECKS` and the first // `MemorySafetyCheck::kNone` serves a default value for `DISABLED_CHECKS`. // When 0 arg provided, both of `MemorySafetyCheck::kNone`s serve as default // values for `ENABLED_CHECKS` and `DISABLED_CHECKS` accordingly. #define ADVANCED_MEMORY_SAFETY_CHECKS(...) … #else #define ADVANCED_MEMORY_SAFETY_CHECKS … #endif // DCHECK_IS_ON() // When a struct/class with `ADVANCED_MEMORY_SAFETY_CHECKS()` is inherited, a // derived struct/class operator will use customized `operator new()` and // `operator delete()` too. If a class has multiple base classes with the macro, // a compiler may complain ambiguity between multiple `operator new()`s. On the // other hand, if a class uses private inheritance, a compiler may report // private `operator new()` that is making impossible to `new` that class. We // have two utility macros to resolve these issues: // - `INHERIT_MEMORY_SAFETY_CHECKS(BaseClass)` // Explicitly exports operators from given `BaseClass` to re-apply // checks specified in the parent class. This is the recommended option as // a derived class is likely to have the same characteristics to its baes // class. This macro accepts additional arguments to overwrite // `BaseClass`'s opted-in checks. // ``` // INHERIT_MEMORY_SAFETY_CHECKS(BaseClass, // /*enable=*/ kFoo | kBar, // /*disable=*/ kBaz); // ``` // - `DEFAULT_MEMORY_SAFETY_CHECKS()` // Re-define default `operator new()` and `operator delete()` using // global operators that comes with default checks. This macro accepts // additional arguments to enable some checks manually. // ``` // DEFAULT_MEMORY_SAFETY_CHECKS(BaseClass, // /*enable=*/ kFoo | kBar); // ``` // // Note that if you use these macros at the top of struct declaration, the // declaration context would be left as |private|. Please switch it back to // |public| manually if needed. #define INHERIT_MEMORY_SAFETY_CHECKS(BASE_CLASS, ...) … #define DEFAULT_MEMORY_SAFETY_CHECKS(...) … #endif // BASE_MEMORY_SAFETY_CHECKS_H_