• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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