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