tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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