1 // Copyright 2024 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_MEMORY_SHARED_MEMORY_SAFETY_CHECKER_H_ 6 #define BASE_MEMORY_SHARED_MEMORY_SAFETY_CHECKER_H_ 7 8 #include <array> 9 #include <atomic> 10 #include <type_traits> 11 12 #include "base/containers/span.h" 13 14 namespace base::subtle { 15 16 // Constraints on types that can be copied across memory spaces. This is a 17 // non-exhaustive list and further constraints may be added in the future. 18 19 // `kIsAllowed` is true unless T is known to be dangerous over shared memory. 20 template <typename T> 21 struct SharedMemorySafetyChecker { 22 // Copying non-trivially-copyable objects across memory spaces is dangerous. 23 // This check isn't a separate specialization because many types that match 24 // other specializations are also trivially copyable, introducing ambiguity. 25 static constexpr bool kIsAllowed = std::is_trivially_copyable_v<T>; 26 }; 27 28 // Pointers can't be shared across memory spaces. 29 template <typename T> 30 requires(std::is_pointer_v<T> || std::is_member_pointer_v<T>) 31 struct SharedMemorySafetyChecker<T> { 32 static constexpr bool kIsAllowed = false; 33 }; 34 35 // Spans can't be shared across memory spaces. 36 template <typename ElementType, size_t Extent, typename InternalPtrType> 37 struct SharedMemorySafetyChecker<span<ElementType, Extent, InternalPtrType>> { 38 static constexpr bool kIsAllowed = false; 39 }; 40 41 // Atomics are dangerous to share across memory spaces unless they're lock-free. 42 template <typename T> 43 struct SharedMemorySafetyChecker<std::atomic<T>> { 44 static constexpr bool kIsAllowed = std::atomic<T>::is_always_lock_free && 45 SharedMemorySafetyChecker<T>::kIsAllowed; 46 }; 47 48 // Each element of an array must itself be safe. Although arrays aren't outright 49 // banned, prefer to use GetMemoryAsSpan<T> for array-like access. 50 template <typename T, size_t N> 51 struct SharedMemorySafetyChecker<T[N]> { 52 static constexpr bool kIsAllowed = SharedMemorySafetyChecker<T>::kIsAllowed; 53 }; 54 55 template <typename T, size_t N> 56 struct SharedMemorySafetyChecker<std::array<T, N>> { 57 static constexpr bool kIsAllowed = SharedMemorySafetyChecker<T>::kIsAllowed; 58 }; 59 60 template <typename T> 61 concept AllowedOverSharedMemory = SharedMemorySafetyChecker<T>::kIsAllowed; 62 63 // Convenience alias for atomics that are safe to share across memory spaces. 64 template <typename T> 65 requires AllowedOverSharedMemory<std::atomic<T>> 66 using SharedAtomic = std::atomic<T>; 67 68 } // namespace base::subtle 69 70 #endif // BASE_MEMORY_SHARED_MEMORY_SAFETY_CHECKER_H_ 71