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