BigBuffer.cpp (3711B)
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 #include "mozilla/ipc/BigBuffer.h" 8 9 #include "chrome/common/ipc_message_utils.h" 10 #include "nsDebug.h" 11 12 namespace mozilla::ipc { 13 14 BigBuffer::BigBuffer(Adopt, SharedMemoryMappingWithHandle&& aSharedMemory, 15 size_t aSize) 16 : mSize(aSize), mData(AsVariant(std::move(aSharedMemory))) { 17 MOZ_RELEASE_ASSERT(mData.as<1>(), "shared memory must be valid"); 18 MOZ_RELEASE_ASSERT(mSize <= mData.as<1>().Size(), 19 "shared memory region isn't large enough"); 20 } 21 22 BigBuffer::BigBuffer(Adopt, uint8_t* aData, size_t aSize) 23 : mSize(aSize), mData(AsVariant(UniqueFreePtr<uint8_t[]>{aData})) {} 24 25 uint8_t* BigBuffer::Data() { 26 return mData.is<0>() ? mData.as<0>().get() : mData.as<1>().DataAs<uint8_t>(); 27 } 28 const uint8_t* BigBuffer::Data() const { 29 return mData.is<0>() ? mData.as<0>().get() 30 : mData.as<1>().DataAs<const uint8_t>(); 31 } 32 33 auto BigBuffer::TryAllocBuffer(size_t aSize) -> Maybe<Storage> { 34 if (aSize <= kShmemThreshold) { 35 auto mem = UniqueFreePtr<uint8_t[]>{ 36 reinterpret_cast<uint8_t*>(malloc(aSize))}; // Fallible! 37 if (!mem) return {}; 38 return Some(AsVariant(std::move(mem))); 39 } 40 41 size_t capacity = shared_memory::PageAlignedSize(aSize); 42 auto mapping = shared_memory::Create(capacity).MapWithHandle(); 43 if (!mapping) { 44 return {}; 45 } 46 return Some(AsVariant(std::move(mapping))); 47 } 48 49 } // namespace mozilla::ipc 50 51 void IPC::ParamTraits<mozilla::ipc::BigBuffer>::Write(MessageWriter* aWriter, 52 paramType&& aParam) { 53 using namespace mozilla::ipc; 54 size_t size = std::exchange(aParam.mSize, 0); 55 auto data = std::exchange(aParam.mData, BigBuffer::NoData()); 56 57 WriteParam(aWriter, size); 58 bool isShmem = data.is<1>(); 59 WriteParam(aWriter, isShmem); 60 61 if (isShmem) { 62 auto handle = data.as<1>().Handle().Clone(); 63 if (!handle) { 64 aWriter->FatalError("Failed to write data shmem"); 65 } else { 66 WriteParam(aWriter, std::move(handle)); 67 } 68 } else { 69 aWriter->WriteBytes(data.as<0>().get(), size); 70 } 71 } 72 73 bool IPC::ParamTraits<mozilla::ipc::BigBuffer>::Read(MessageReader* aReader, 74 paramType* aResult) { 75 using namespace mozilla::ipc; 76 size_t size = 0; 77 bool isShmem = false; 78 if (!ReadParam(aReader, &size) || !ReadParam(aReader, &isShmem)) { 79 aReader->FatalError("Failed to read data size and format"); 80 return false; 81 } 82 83 if (isShmem) { 84 MutableSharedMemoryHandle handle; 85 size_t expected_size = shared_memory::PageAlignedSize(size); 86 if (!ReadParam(aReader, &handle) || !handle) { 87 aReader->FatalError("Failed to read data shmem"); 88 return false; 89 } 90 auto mapping = std::move(handle).MapWithHandle(); 91 if (!mapping || mapping.Size() != expected_size) { 92 aReader->FatalError("Failed to map data shmem"); 93 return false; 94 } 95 *aResult = BigBuffer(BigBuffer::Adopt{}, std::move(mapping), size); 96 return true; 97 } 98 99 mozilla::UniqueFreePtr<uint8_t[]> buf{ 100 reinterpret_cast<uint8_t*>(malloc(size))}; 101 if (!buf) { 102 aReader->FatalError("Failed to allocate data buffer"); 103 return false; 104 } 105 if (!aReader->ReadBytesInto(buf.get(), size)) { 106 aReader->FatalError("Failed to read data"); 107 return false; 108 } 109 *aResult = BigBuffer(BigBuffer::Adopt{}, buf.release(), size); 110 return true; 111 }