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