SharedMemoryHandle.cpp (6982B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* This source code was derived from Chromium code, and as such is also subject 8 * to the [Chromium license](ipc/chromium/src/LICENSE). */ 9 10 #include "mozilla/ipc/SharedMemoryHandle.h" 11 #include "mozilla/ipc/SharedMemoryMapping.h" 12 #include "SharedMemoryPlatform.h" 13 14 #include "chrome/common/ipc_message_utils.h" 15 #include "mozilla/Atomics.h" 16 #include "nsDebug.h" 17 #include "nsIMemoryReporter.h" 18 19 namespace mozilla::ipc::shared_memory { 20 21 // Implementation of the shared memory logger in SharedMemoryPlatform.h. 22 LazyLogModule gSharedMemoryLog{"SharedMemory"}; 23 24 class AllocationReporter final : public nsIMemoryReporter { 25 ~AllocationReporter() = default; 26 27 public: 28 static Atomic<uint64_t> allocated; 29 30 NS_DECL_THREADSAFE_ISUPPORTS 31 32 NS_IMETHOD 33 CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, 34 bool aAnonymize) override { 35 MOZ_COLLECT_REPORT( 36 "shmem-allocated", KIND_OTHER, UNITS_BYTES, allocated, 37 "Memory shared with other processes that is accessible (but not " 38 "necessarily mapped)."); 39 40 return NS_OK; 41 } 42 }; 43 44 Atomic<uint64_t> AllocationReporter::allocated; 45 46 NS_IMPL_ISUPPORTS(AllocationReporter, nsIMemoryReporter) 47 48 static void RegisterAllocationMemoryReporter() { 49 static Atomic<bool> registered; 50 if (registered.compareExchange(false, true)) { 51 RegisterStrongMemoryReporter(new AllocationReporter()); 52 } 53 } 54 55 HandleBase::HandleBase() = default; 56 57 HandleBase::~HandleBase() { 58 if (mSize > 0) { 59 MOZ_ASSERT(AllocationReporter::allocated >= mSize, 60 "Can't destroy more than allocated"); 61 SetSize(0); 62 } 63 mHandle = nullptr; 64 } 65 66 HandleBase& HandleBase::operator=(HandleBase&& aOther) { 67 mHandle = std::move(aOther.mHandle); 68 SetSize(std::exchange(aOther.mSize, 0)); 69 return *this; 70 } 71 72 HandleBase HandleBase::Clone() const { 73 HandleBase hb; 74 hb.mHandle = Platform::CloneHandle(mHandle); 75 if (hb.mHandle) { 76 // TODO more intelligently handle clones to not count as additional 77 // allocations? 78 hb.SetSize(mSize); 79 } 80 return hb; 81 } 82 83 void HandleBase::ToMessageWriter(IPC::MessageWriter* aWriter) && { 84 WriteParam(aWriter, std::move(mHandle)); 85 WriteParam(aWriter, mSize); 86 SetSize(0); 87 } 88 89 bool HandleBase::FromMessageReader(IPC::MessageReader* aReader) { 90 mozilla::ipc::shared_memory::PlatformHandle handle; 91 if (!ReadParam(aReader, &handle)) { 92 aReader->FatalError("Failed to read shared memory PlatformHandle"); 93 return false; 94 } 95 if (handle && !Platform::IsSafeToMap(handle)) { 96 aReader->FatalError("Shared memory PlatformHandle is not safe to map"); 97 return false; 98 } 99 uint64_t size = 0; 100 if (!ReadParam(aReader, &size)) { 101 aReader->FatalError("Failed to read shared memory handle size"); 102 return false; 103 } 104 if (handle && !size) { 105 aReader->FatalError( 106 "Unexpected PlatformHandle for zero-sized shared memory handle"); 107 return false; 108 } 109 mHandle = std::move(handle); 110 SetSize(size); 111 return true; 112 } 113 114 void HandleBase::SetSize(uint64_t aSize) { 115 RegisterAllocationMemoryReporter(); 116 mozilla::ipc::shared_memory::AllocationReporter::allocated -= mSize; 117 mSize = aSize; 118 mozilla::ipc::shared_memory::AllocationReporter::allocated += mSize; 119 } 120 121 MutableMapping MutableHandle::Map(void* aFixedAddress) const { 122 return MutableMapping(*this, aFixedAddress); 123 } 124 125 MutableMapping MutableHandle::MapSubregion(uint64_t aOffset, size_t aSize, 126 void* aFixedAddress) const { 127 return MutableMapping(*this, aOffset, aSize, aFixedAddress); 128 } 129 130 MutableMappingWithHandle MutableHandle::MapWithHandle(void* aFixedAddress) && { 131 return MutableMappingWithHandle(std::move(*this), aFixedAddress); 132 } 133 134 ReadOnlyHandle MutableHandle::ToReadOnly() && { 135 return std::move(*this).ConvertTo<Type::ReadOnly>(); 136 } 137 138 const ReadOnlyHandle& MutableHandle::AsReadOnly() const { 139 static_assert(sizeof(ReadOnlyHandle) == sizeof(MutableHandle)); 140 return reinterpret_cast<const ReadOnlyHandle&>(*this); 141 } 142 143 ReadOnlyMapping ReadOnlyHandle::Map(void* aFixedAddress) const { 144 return ReadOnlyMapping(*this, aFixedAddress); 145 } 146 147 ReadOnlyMapping ReadOnlyHandle::MapSubregion(uint64_t aOffset, size_t aSize, 148 void* aFixedAddress) const { 149 return ReadOnlyMapping(*this, aOffset, aSize, aFixedAddress); 150 } 151 152 ReadOnlyMappingWithHandle ReadOnlyHandle::MapWithHandle( 153 void* aFixedAddress) && { 154 return ReadOnlyMappingWithHandle(std::move(*this), aFixedAddress); 155 } 156 157 FreezableHandle::~Handle() { 158 NS_WARNING_ASSERTION(!IsValid(), "freezable shared memory was never frozen"); 159 } 160 161 MutableHandle FreezableHandle::WontFreeze() && { 162 return std::move(*this).ConvertTo<Type::Mutable>(); 163 } 164 165 ReadOnlyHandle FreezableHandle::Freeze() && { 166 DebugOnly<const uint64_t> previous_size = Size(); 167 if (Platform::Freeze(*this)) { 168 MOZ_ASSERT(Size() == previous_size); 169 return std::move(*this).ConvertTo<Type::ReadOnly>(); 170 } 171 return nullptr; 172 } 173 174 FreezableMapping FreezableHandle::Map(void* aFixedAddress) && { 175 return FreezableMapping(std::move(*this), aFixedAddress); 176 } 177 178 FreezableMapping FreezableHandle::MapSubregion(uint64_t aOffset, size_t aSize, 179 void* aFixedAddress) && { 180 return FreezableMapping(std::move(*this), aOffset, aSize, aFixedAddress); 181 } 182 183 MutableHandle Create(uint64_t aSize) { 184 MutableHandle h; 185 const auto success = Platform::Create(h, aSize); 186 MOZ_ASSERT(success == h.IsValid()); 187 if (success) { 188 MOZ_ASSERT(aSize == h.Size()); 189 } 190 return h; 191 } 192 193 FreezableHandle CreateFreezable(uint64_t aSize) { 194 FreezableHandle h; 195 const auto success = Platform::CreateFreezable(h, aSize); 196 MOZ_ASSERT(success == h.IsValid()); 197 if (success) { 198 MOZ_ASSERT(aSize == h.Size()); 199 } 200 return h; 201 } 202 203 } // namespace mozilla::ipc::shared_memory 204 205 namespace IPC { 206 207 void ParamTraits<mozilla::ipc::shared_memory::MutableHandle>::Write( 208 MessageWriter* aWriter, 209 mozilla::ipc::shared_memory::MutableHandle&& aParam) { 210 std::move(aParam).ToMessageWriter(aWriter); 211 } 212 213 bool ParamTraits<mozilla::ipc::shared_memory::MutableHandle>::Read( 214 MessageReader* aReader, 215 mozilla::ipc::shared_memory::MutableHandle* aResult) { 216 return aResult->FromMessageReader(aReader); 217 } 218 219 void ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>::Write( 220 MessageWriter* aWriter, 221 mozilla::ipc::shared_memory::ReadOnlyHandle&& aParam) { 222 std::move(aParam).ToMessageWriter(aWriter); 223 } 224 225 bool ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>::Read( 226 MessageReader* aReader, 227 mozilla::ipc::shared_memory::ReadOnlyHandle* aResult) { 228 return aResult->FromMessageReader(aReader); 229 } 230 231 } // namespace IPC