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