• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
10 #include "base/base_export.h"
11 #include "base/check.h"
12 #include "base/compiler_specific.h"
13 #include "base/containers/checked_iterators.h"
14 #include "base/containers/span.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/memory/raw_span.h"
17 #include "base/memory/shared_memory_mapper.h"
18 #include "base/memory/shared_memory_safety_checker.h"
19 #include "base/unguessable_token.h"
20 
21 namespace base {
22 
23 namespace subtle {
24 class PlatformSharedMemoryRegion;
25 }  // namespace subtle
26 
27 // Base class for scoped handles to a shared memory mapping created from a
28 // shared memory region. Created shared memory mappings remain valid even if the
29 // creator region is transferred or destroyed.
30 //
31 // Each mapping has an UnguessableToken that identifies the shared memory region
32 // it was created from. This is used for memory metrics, to avoid overcounting
33 // shared memory.
34 class BASE_EXPORT SharedMemoryMapping {
35  public:
36   // Default constructor initializes an invalid instance.
37   SharedMemoryMapping();
38 
39   // Move operations are allowed.
40   SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept;
41   SharedMemoryMapping& operator=(SharedMemoryMapping&& mapping) noexcept;
42 
43   SharedMemoryMapping(const SharedMemoryMapping&) = delete;
44   SharedMemoryMapping& operator=(const SharedMemoryMapping&) = delete;
45 
46   // Unmaps the region if the mapping is valid.
47   virtual ~SharedMemoryMapping();
48 
49   // Returns true iff the mapping is valid. False means there is no
50   // corresponding area of memory.
IsValid()51   bool IsValid() const { return !mapped_span_.empty(); }
52 
53   // Returns the logical size of the mapping in bytes. This is precisely the
54   // size requested by whoever created the mapping, and it is always less than
55   // or equal to |mapped_size()|. This is undefined for invalid instances.
size()56   size_t size() const {
57     DCHECK(IsValid());
58     return size_;
59   }
60 
61   // Returns the actual size of the mapping in bytes. This is always at least
62   // as large as |size()| but may be larger due to platform mapping alignment
63   // constraints. This is undefined for invalid instances.
mapped_size()64   size_t mapped_size() const {
65     DCHECK(IsValid());
66     return mapped_span_.size();
67   }
68 
69   // Returns 128-bit GUID of the region this mapping belongs to.
guid()70   const UnguessableToken& guid() const LIFETIME_BOUND {
71     DCHECK(IsValid());
72     return guid_;
73   }
74 
75  protected:
76   SharedMemoryMapping(span<uint8_t> mapped_span,
77                       size_t size,
78                       const UnguessableToken& guid,
79                       SharedMemoryMapper* mapper);
80 
81   // Returns a span over the full mapped memory.
mapped_memory()82   span<uint8_t> mapped_memory() const { return mapped_span_; }
83 
84  private:
85   friend class SharedMemoryTracker;
86 
87   void Unmap();
88 
89   raw_span<uint8_t> mapped_span_;
90   size_t size_ = 0;
91   UnguessableToken guid_;
92   raw_ptr<SharedMemoryMapper> mapper_ = nullptr;
93 };
94 
95 // Class modeling a read-only mapping of a shared memory region into the
96 // current process' address space. This is created by ReadOnlySharedMemoryRegion
97 // instances.
98 class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
99  public:
100   using iterator = base::CheckedContiguousIterator<const uint8_t>;
101 
102   // Default constructor initializes an invalid instance.
103   ReadOnlySharedMemoryMapping();
104 
105   ReadOnlySharedMemoryMapping(const ReadOnlySharedMemoryMapping&) = delete;
106   ReadOnlySharedMemoryMapping& operator=(const ReadOnlySharedMemoryMapping&) =
107       delete;
108 
109   // Move operations are allowed.
110   ReadOnlySharedMemoryMapping(ReadOnlySharedMemoryMapping&&) noexcept;
111   ReadOnlySharedMemoryMapping& operator=(
112       ReadOnlySharedMemoryMapping&&) noexcept;
113 
114   // Returns the base address of the read-only mapping. Returns nullptr for
115   // invalid instances.
116   //
117   // Use `span(mapping)` to make a span of `uint8_t`, `GetMemoryAs<T>()` to
118   // access the memory as a single `T` or `GetMemoryAsSpan<T>()` to access it as
119   // an array of `T`.
data()120   const uint8_t* data() const { return mapped_memory().data(); }
121 
122   // Iterate memory as bytes up to the end of its logical size.
begin()123   iterator begin() const {
124     // SAFETY: There is an internal invariant (enforced in the constructors)
125     // that `size() <= mapped_memory().size()`, so `data()` points to at least
126     // that many valid bytes.
127     return UNSAFE_BUFFERS(iterator(data(), data() + size()));
128   }
end()129   iterator end() const {
130     // SAFETY: As in `begin()` above.
131     return UNSAFE_BUFFERS(iterator(data(), data() + size(), data() + size()));
132   }
133 
134   // TODO(crbug.com/355451178): Deprecated. Use `span(mapping)` to make a span
135   // of `uint8_t`, `GetMemoryAs<T>()` to access the memory as a single `T` or
136   // `GetMemoryAsSpan<T>()` to access it as an array of `T`, or `data()` for an
137   // unbounded pointer.
memory()138   const void* memory() const { return data(); }
139 
140   // Returns a pointer to a page-aligned const T if the mapping is valid and
141   // large enough to contain a T, or nullptr otherwise.
142   template <typename T>
143     requires subtle::AllowedOverSharedMemory<T>
GetMemoryAs()144   const T* GetMemoryAs() const {
145     if (!IsValid())
146       return nullptr;
147     if (sizeof(T) > size())
148       return nullptr;
149     return reinterpret_cast<const T*>(mapped_memory().data());
150   }
151 
152   // Returns a span of const T. The number of elements is autodeduced from the
153   // size of the shared memory mapping. The number of elements may be
154   // autodeduced as zero, i.e. the mapping is invalid or the size of the mapping
155   // isn't large enough to contain even one T: in that case, an empty span
156   // will be returned. The first element, if any, is guaranteed to be
157   // page-aligned.
158   template <typename T>
159     requires subtle::AllowedOverSharedMemory<T>
GetMemoryAsSpan()160   span<const T> GetMemoryAsSpan() const {
161     if (!IsValid())
162       return span<const T>();
163     size_t count = size() / sizeof(T);
164     return GetMemoryAsSpan<T>(count);
165   }
166 
167   // Returns a span of const T with |count| elements if the mapping is valid and
168   // large enough to contain |count| elements, or an empty span otherwise. The
169   // first element, if any, is guaranteed to be page-aligned.
170   template <typename T>
171     requires subtle::AllowedOverSharedMemory<T>
GetMemoryAsSpan(size_t count)172   span<const T> GetMemoryAsSpan(size_t count) const {
173     if (!IsValid())
174       return span<const T>();
175     if (size() / sizeof(T) < count)
176       return span<const T>();
177     // SAFETY: There is an internal invariant (enforced in the constructors)
178     // that `size() <= mapped_memory().size()`. `count` is the number of objects
179     // of type T that fit within size(), so the pointer given to span() points
180     // to at least that many T objects.
181     return UNSAFE_BUFFERS(
182         span(reinterpret_cast<const T*>(mapped_memory().data()), count));
183   }
184 
185  private:
186   friend class ReadOnlySharedMemoryRegion;
187   ReadOnlySharedMemoryMapping(span<uint8_t> mapped_span,
188                               size_t size,
189                               const UnguessableToken& guid,
190                               SharedMemoryMapper* mapper);
191 };
192 
193 // Class modeling a writable mapping of a shared memory region into the
194 // current process' address space. This is created by *SharedMemoryRegion
195 // instances.
196 class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
197  public:
198   using iterator = base::CheckedContiguousIterator<uint8_t>;
199   using const_iterator = base::CheckedContiguousIterator<const uint8_t>;
200 
201   // Default constructor initializes an invalid instance.
202   WritableSharedMemoryMapping();
203 
204   WritableSharedMemoryMapping(const WritableSharedMemoryMapping&) = delete;
205   WritableSharedMemoryMapping& operator=(const WritableSharedMemoryMapping&) =
206       delete;
207 
208   // Move operations are allowed.
209   WritableSharedMemoryMapping(WritableSharedMemoryMapping&&) noexcept;
210   WritableSharedMemoryMapping& operator=(
211       WritableSharedMemoryMapping&&) noexcept;
212 
213   // Returns the base address of the writable mapping. Returns nullptr for
214   // invalid instances.
215   //
216   // Use `span(mapping)` to make a span of `uint8_t`, `GetMemoryAs<T>()` to
217   // access the memory as a single `T` or `GetMemoryAsSpan<T>()` to access it as
218   // an array of `T`.
data()219   uint8_t* data() { return mapped_memory().data(); }
data()220   const uint8_t* data() const { return mapped_memory().data(); }
221 
222   // Iterate memory as bytes up to the end of its logical size.
begin()223   iterator begin() {
224     // SAFETY: As in the ReadOnly code above.
225     return UNSAFE_BUFFERS(iterator(data(), data() + size()));
226   }
begin()227   const_iterator begin() const {
228     // SAFETY: As in the ReadOnly code above.
229     return UNSAFE_BUFFERS(const_iterator(data(), data() + size()));
230   }
end()231   iterator end() {
232     // SAFETY: As in the ReadOnly code above.
233     return UNSAFE_BUFFERS(iterator(data(), data() + size(), data() + size()));
234   }
end()235   const_iterator end() const {
236     // SAFETY: As in the ReadOnly code above.
237     return UNSAFE_BUFFERS(
238         const_iterator(data(), data() + size(), data() + size()));
239   }
240 
241   // TODO(crbug.com/355451178): Deprecated. Use `span(mapping)` to make a span
242   // of `uint8_t`, `GetMemoryAs<T>()` to access the memory as a single `T`, or
243   // `GetMemoryAsSpan<T>()` to access it as an array of `T` or `data()` for an
244   // unbounded pointer.
memory()245   void* memory() { return data(); }
memory()246   const void* memory() const { return data(); }
247 
248   // Returns a pointer to a page-aligned T if the mapping is valid and large
249   // enough to contain a T, or nullptr otherwise.
250   template <typename T>
251     requires subtle::AllowedOverSharedMemory<T>
GetMemoryAs()252   T* GetMemoryAs() const {
253     if (!IsValid())
254       return nullptr;
255     if (sizeof(T) > size())
256       return nullptr;
257     return reinterpret_cast<T*>(mapped_memory().data());
258   }
259 
260   // Returns a span of T. The number of elements is autodeduced from the size of
261   // the shared memory mapping. The number of elements may be autodeduced as
262   // zero, i.e. the mapping is invalid or the size of the mapping isn't large
263   // enough to contain even one T: in that case, an empty span will be returned.
264   // The first element, if any, is guaranteed to be page-aligned.
265   template <typename T>
266     requires subtle::AllowedOverSharedMemory<T>
GetMemoryAsSpan()267   span<T> GetMemoryAsSpan() const {
268     if (!IsValid())
269       return span<T>();
270     size_t count = size() / sizeof(T);
271     return GetMemoryAsSpan<T>(count);
272   }
273 
274   // Returns a span of T with |count| elements if the mapping is valid and large
275   // enough to contain |count| elements, or an empty span otherwise. The first
276   // element, if any, is guaranteed to be page-aligned.
277   template <typename T>
278     requires subtle::AllowedOverSharedMemory<T>
GetMemoryAsSpan(size_t count)279   span<T> GetMemoryAsSpan(size_t count) const {
280     if (!IsValid())
281       return span<T>();
282     if (size() / sizeof(T) < count)
283       return span<T>();
284     // SAFETY: There is an internal invariant (enforced in the constructors)
285     // that `size() <= mapped_memory().size()`. `count` is the number of objects
286     // of type T that fit within size(), so the pointer given to span() points
287     // to at least that many T objects.
288     return UNSAFE_BUFFERS(
289         span(reinterpret_cast<T*>(mapped_memory().data()), count));
290   }
291 
292  private:
293   friend WritableSharedMemoryMapping MapAtForTesting(
294       subtle::PlatformSharedMemoryRegion* region,
295       uint64_t offset,
296       size_t size);
297   friend class ReadOnlySharedMemoryRegion;
298   friend class WritableSharedMemoryRegion;
299   friend class UnsafeSharedMemoryRegion;
300   WritableSharedMemoryMapping(span<uint8_t> mapped_span,
301                               size_t size,
302                               const UnguessableToken& guid,
303                               SharedMemoryMapper* mapper);
304 
305   friend class DiscardableSharedMemory;  // Give access to mapped_memory().
306 };
307 
308 }  // namespace base
309 
310 #endif  // BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
311