xref: /aosp_15_r20/external/cronet/base/memory/shared_memory_mapping.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 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_MAPPING_H_
6 #define BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
7 
8 #include <cstddef>
9 #include <type_traits>
10 
11 #include "base/base_export.h"
12 #include "base/check.h"
13 #include "base/containers/span.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/shared_memory_mapper.h"
16 #include "base/unguessable_token.h"
17 
18 namespace base {
19 
20 namespace subtle {
21 class PlatformSharedMemoryRegion;
22 }  // namespace subtle
23 
24 // Base class for scoped handles to a shared memory mapping created from a
25 // shared memory region. Created shared memory mappings remain valid even if the
26 // creator region is transferred or destroyed.
27 //
28 // Each mapping has an UnguessableToken that identifies the shared memory region
29 // it was created from. This is used for memory metrics, to avoid overcounting
30 // shared memory.
31 class BASE_EXPORT SharedMemoryMapping {
32  public:
33   // Default constructor initializes an invalid instance.
34   SharedMemoryMapping();
35 
36   // Move operations are allowed.
37   SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept;
38   SharedMemoryMapping& operator=(SharedMemoryMapping&& mapping) noexcept;
39 
40   SharedMemoryMapping(const SharedMemoryMapping&) = delete;
41   SharedMemoryMapping& operator=(const SharedMemoryMapping&) = delete;
42 
43   // Unmaps the region if the mapping is valid.
44   virtual ~SharedMemoryMapping();
45 
46   // Returns true iff the mapping is valid. False means there is no
47   // corresponding area of memory.
IsValid()48   bool IsValid() const { return !mapped_span_.empty(); }
49 
50   // Returns the logical size of the mapping in bytes. This is precisely the
51   // size requested by whoever created the mapping, and it is always less than
52   // or equal to |mapped_size()|. This is undefined for invalid instances.
size()53   size_t size() const {
54     DCHECK(IsValid());
55     return size_;
56   }
57 
58   // Returns the actual size of the mapping in bytes. This is always at least
59   // as large as |size()| but may be larger due to platform mapping alignment
60   // constraints. This is undefined for invalid instances.
mapped_size()61   size_t mapped_size() const {
62     DCHECK(IsValid());
63     return mapped_span_.size();
64   }
65 
66   // Returns 128-bit GUID of the region this mapping belongs to.
guid()67   const UnguessableToken& guid() const {
68     DCHECK(IsValid());
69     return guid_;
70   }
71 
72  protected:
73   SharedMemoryMapping(span<uint8_t> mapped_span,
74                       size_t size,
75                       const UnguessableToken& guid,
76                       SharedMemoryMapper* mapper);
raw_memory_ptr()77   void* raw_memory_ptr() const {
78     return reinterpret_cast<void*>(mapped_span_.data());
79   }
80 
81  private:
82   friend class SharedMemoryTracker;
83 
84   void Unmap();
85 
86   span<uint8_t> mapped_span_;
87   size_t size_ = 0;
88   UnguessableToken guid_;
89   raw_ptr<SharedMemoryMapper> mapper_ = nullptr;
90 };
91 
92 // Class modeling a read-only mapping of a shared memory region into the
93 // current process' address space. This is created by ReadOnlySharedMemoryRegion
94 // instances.
95 class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
96  public:
97   // Default constructor initializes an invalid instance.
98   ReadOnlySharedMemoryMapping();
99 
100   ReadOnlySharedMemoryMapping(const ReadOnlySharedMemoryMapping&) = delete;
101   ReadOnlySharedMemoryMapping& operator=(const ReadOnlySharedMemoryMapping&) =
102       delete;
103 
104   // Move operations are allowed.
105   ReadOnlySharedMemoryMapping(ReadOnlySharedMemoryMapping&&) noexcept;
106   ReadOnlySharedMemoryMapping& operator=(
107       ReadOnlySharedMemoryMapping&&) noexcept;
108 
109   // Returns the base address of the read-only mapping. Returns nullptr for
110   // invalid instances.
memory()111   const void* memory() const { return raw_memory_ptr(); }
112 
113   // Returns a pointer to a page-aligned const T if the mapping is valid and
114   // large enough to contain a T, or nullptr otherwise.
115   template <typename T>
GetMemoryAs()116   const T* GetMemoryAs() const {
117     static_assert(std::is_trivially_copyable_v<T>,
118                   "Copying non-trivially-copyable object across memory spaces "
119                   "is dangerous");
120     if (!IsValid())
121       return nullptr;
122     if (sizeof(T) > size())
123       return nullptr;
124     return static_cast<const T*>(raw_memory_ptr());
125   }
126 
127   // Returns a span of const T. The number of elements is autodeduced from the
128   // size of the shared memory mapping. The number of elements may be
129   // autodeduced as zero, i.e. the mapping is invalid or the size of the mapping
130   // isn't large enough to contain even one T: in that case, an empty span
131   // will be returned. The first element, if any, is guaranteed to be
132   // page-aligned.
133   template <typename T>
GetMemoryAsSpan()134   span<const T> GetMemoryAsSpan() const {
135     static_assert(std::is_trivially_copyable_v<T>,
136                   "Copying non-trivially-copyable object across memory spaces "
137                   "is dangerous");
138     if (!IsValid())
139       return span<const T>();
140     size_t count = size() / sizeof(T);
141     return GetMemoryAsSpan<T>(count);
142   }
143 
144   // Returns a span of const T with |count| elements if the mapping is valid and
145   // large enough to contain |count| elements, or an empty span otherwise. The
146   // first element, if any, is guaranteed to be page-aligned.
147   template <typename T>
GetMemoryAsSpan(size_t count)148   span<const T> GetMemoryAsSpan(size_t count) const {
149     static_assert(std::is_trivially_copyable_v<T>,
150                   "Copying non-trivially-copyable object across memory spaces "
151                   "is dangerous");
152     if (!IsValid())
153       return span<const T>();
154     if (size() / sizeof(T) < count)
155       return span<const T>();
156     return span<const T>(static_cast<const T*>(raw_memory_ptr()), count);
157   }
158 
159  private:
160   friend class ReadOnlySharedMemoryRegion;
161   ReadOnlySharedMemoryMapping(span<uint8_t> mapped_span,
162                               size_t size,
163                               const UnguessableToken& guid,
164                               SharedMemoryMapper* mapper);
165 };
166 
167 // Class modeling a writable mapping of a shared memory region into the
168 // current process' address space. This is created by *SharedMemoryRegion
169 // instances.
170 class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
171  public:
172   // Default constructor initializes an invalid instance.
173   WritableSharedMemoryMapping();
174 
175   WritableSharedMemoryMapping(const WritableSharedMemoryMapping&) = delete;
176   WritableSharedMemoryMapping& operator=(const WritableSharedMemoryMapping&) =
177       delete;
178 
179   // Move operations are allowed.
180   WritableSharedMemoryMapping(WritableSharedMemoryMapping&&) noexcept;
181   WritableSharedMemoryMapping& operator=(
182       WritableSharedMemoryMapping&&) noexcept;
183 
184   // Returns the base address of the writable mapping. Returns nullptr for
185   // invalid instances.
memory()186   void* memory() const { return raw_memory_ptr(); }
187 
188   // Returns a pointer to a page-aligned T if the mapping is valid and large
189   // enough to contain a T, or nullptr otherwise.
190   template <typename T>
GetMemoryAs()191   T* GetMemoryAs() const {
192     static_assert(std::is_trivially_copyable_v<T>,
193                   "Copying non-trivially-copyable object across memory spaces "
194                   "is dangerous");
195     if (!IsValid())
196       return nullptr;
197     if (sizeof(T) > size())
198       return nullptr;
199     return static_cast<T*>(raw_memory_ptr());
200   }
201 
202   // Returns a span of T. The number of elements is autodeduced from the size of
203   // the shared memory mapping. The number of elements may be autodeduced as
204   // zero, i.e. the mapping is invalid or the size of the mapping isn't large
205   // enough to contain even one T: in that case, an empty span will be returned.
206   // The first element, if any, is guaranteed to be page-aligned.
207   template <typename T>
GetMemoryAsSpan()208   span<T> GetMemoryAsSpan() const {
209     static_assert(std::is_trivially_copyable_v<T>,
210                   "Copying non-trivially-copyable object across memory spaces "
211                   "is dangerous");
212     if (!IsValid())
213       return span<T>();
214     size_t count = size() / sizeof(T);
215     return GetMemoryAsSpan<T>(count);
216   }
217 
218   // Returns a span of T with |count| elements if the mapping is valid and large
219   // enough to contain |count| elements, or an empty span otherwise. The first
220   // element, if any, is guaranteed to be page-aligned.
221   template <typename T>
GetMemoryAsSpan(size_t count)222   span<T> GetMemoryAsSpan(size_t count) const {
223     static_assert(std::is_trivially_copyable_v<T>,
224                   "Copying non-trivially-copyable object across memory spaces "
225                   "is dangerous");
226     if (!IsValid())
227       return span<T>();
228     if (size() / sizeof(T) < count)
229       return span<T>();
230     return span<T>(static_cast<T*>(raw_memory_ptr()), count);
231   }
232 
233  private:
234   friend WritableSharedMemoryMapping MapAtForTesting(
235       subtle::PlatformSharedMemoryRegion* region,
236       uint64_t offset,
237       size_t size);
238   friend class ReadOnlySharedMemoryRegion;
239   friend class WritableSharedMemoryRegion;
240   friend class UnsafeSharedMemoryRegion;
241   WritableSharedMemoryMapping(span<uint8_t> mapped_span,
242                               size_t size,
243                               const UnguessableToken& guid,
244                               SharedMemoryMapper* mapper);
245 };
246 
247 }  // namespace base
248 
249 #endif  // BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
250