tor-browser

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

BigBuffer.h (4346B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_ipc_BigBuffer_h
      8 #define mozilla_ipc_BigBuffer_h
      9 
     10 #include <stdlib.h>
     11 #include <inttypes.h>
     12 #include "nsDebug.h"
     13 #include "mozilla/Maybe.h"
     14 #include "mozilla/Span.h"
     15 #include "mozilla/Variant.h"
     16 #include "mozilla/ipc/SharedMemoryMapping.h"
     17 
     18 namespace mozilla::ipc {
     19 
     20 class BigBuffer {
     21 public:
     22  static constexpr size_t kShmemThreshold = 64 * 1024;
     23 
     24  static BigBuffer TryAlloc(const size_t aSize) {
     25    auto ret = BigBuffer{};
     26    auto data = TryAllocBuffer(aSize);
     27    if (data) {
     28      ret.mSize = aSize;
     29      ret.mData = std::move(data.ref());
     30    }
     31    return ret;
     32  }
     33 
     34  // Return a new BigBuffer which wraps no data.
     35  BigBuffer() : mSize(0), mData(NoData()) {}
     36 
     37  BigBuffer(const BigBuffer&) = delete;
     38  BigBuffer& operator=(const BigBuffer&) = delete;
     39 
     40  BigBuffer(BigBuffer&& aOther) noexcept
     41      : mSize(std::exchange(aOther.mSize, 0)),
     42        mData(std::exchange(aOther.mData, NoData())) {}
     43 
     44  BigBuffer& operator=(BigBuffer&& aOther) noexcept {
     45    mSize = std::exchange(aOther.mSize, 0);
     46    mData = std::exchange(aOther.mData, NoData());
     47    return *this;
     48  }
     49 
     50  // Create a new BigBuffer with the given size.
     51  // The buffer will be created uninitialized and must be fully initialized
     52  // before sending over IPC to avoid leaking uninitialized memory to another
     53  // process.
     54  explicit BigBuffer(size_t aSize) : mSize(aSize), mData(AllocBuffer(aSize)) {}
     55 
     56  // Create a new BigBuffer containing the data from the provided byte slice.
     57  explicit BigBuffer(Span<const uint8_t> aData) : BigBuffer(aData.Length()) {
     58    memcpy(Data(), aData.Elements(), aData.Length());
     59  }
     60 
     61  // Marker to indicate that a particular constructor of BigBuffer adopts
     62  // ownership of the provided data.
     63  struct Adopt {};
     64 
     65  // Create a new BigBuffer from an existing shared memory region, taking
     66  // ownership of that shared memory region. The shared memory region must be
     67  // valid and large enough to fit aSize bytes.
     68  BigBuffer(Adopt, SharedMemoryMappingWithHandle&& aSharedMemory, size_t aSize);
     69 
     70  // Create a new BigBuffer from an existing memory buffer, taking ownership of
     71  // that memory region. The region will be freed using `free()` when it is no
     72  // longer needed.
     73  BigBuffer(Adopt, uint8_t* aData, size_t aSize);
     74 
     75  ~BigBuffer() = default;
     76 
     77  // Returns a pointer to the data stored by this BigBuffer, regardless of
     78  // backing storage type.
     79  uint8_t* Data();
     80  const uint8_t* Data() const;
     81 
     82  // Returns the size of the data stored by this BigBuffer, regardless of
     83  // backing storage type.
     84  size_t Size() const { return mSize; }
     85 
     86  // Get a view of the BigBuffer's data as a span.
     87  Span<uint8_t> AsSpan() { return Span{Data(), Size()}; }
     88  Span<const uint8_t> AsSpan() const { return Span{Data(), Size()}; }
     89 
     90  // If the BigBuffer is backed by shared memory, returns a pointer to the
     91  // backing SharedMemory region.
     92  // This is only meant to be used in tests.
     93  const SharedMemoryMappingWithHandle* GetSharedMemory() const {
     94    return mData.is<1>() ? &mData.as<1>() : nullptr;
     95  }
     96 
     97 private:
     98  friend struct IPC::ParamTraits<mozilla::ipc::BigBuffer>;
     99 
    100  using Storage =
    101      Variant<UniqueFreePtr<uint8_t[]>, SharedMemoryMappingWithHandle>;
    102 
    103  // Empty storage which holds no data.
    104  static Storage NoData() { return AsVariant(UniqueFreePtr<uint8_t[]>{}); }
    105 
    106  // Fallibly allocate a new storage of the given size.
    107  static Maybe<Storage> TryAllocBuffer(size_t aSize);
    108 
    109  // Infallibly allocate a new storage of the given size.
    110  static Storage AllocBuffer(size_t aSize) {
    111    auto ret = TryAllocBuffer(aSize);
    112    if (!ret) {
    113      NS_ABORT_OOM(aSize);
    114    }
    115    return std::move(ret.ref());
    116  }
    117 
    118  size_t mSize;
    119  Storage mData;
    120 };
    121 
    122 }  // namespace mozilla::ipc
    123 
    124 namespace IPC {
    125 
    126 template <>
    127 struct ParamTraits<mozilla::ipc::BigBuffer> {
    128  using paramType = mozilla::ipc::BigBuffer;
    129  static void Write(MessageWriter* aWriter, paramType&& aParam);
    130  static bool Read(MessageReader* aReader, paramType* aResult);
    131 };
    132 
    133 }  // namespace IPC
    134 
    135 #endif  // mozilla_BigBuffer_h