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