| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "mojo/public/cpp/bindings/lib/buffer.h" |
| |
| #include "base/logging.h" |
| #include "base/numerics/safe_math.h" |
| #include "mojo/public/c/system/message_pipe.h" |
| #include "mojo/public/cpp/bindings/lib/bindings_internal.h" |
| |
| namespace mojo { |
| namespace internal { |
| |
| Buffer::Buffer() = default; |
| |
| Buffer::Buffer(void* data, size_t size, size_t cursor) |
| : data_(data), size_(size), cursor_(cursor) { |
| DCHECK(IsAligned(data_)); |
| } |
| |
| Buffer::Buffer(MessageHandle message, |
| size_t message_payload_size, |
| void* data, |
| size_t size) |
| : message_(message), |
| message_payload_size_(message_payload_size), |
| data_(data), |
| size_(size), |
| cursor_(0) { |
| DCHECK(IsAligned(data_)); |
| } |
| |
| Buffer::Buffer(Buffer&& other) { |
| *this = std::move(other); |
| } |
| |
| Buffer::~Buffer() = default; |
| |
| Buffer& Buffer::operator=(Buffer&& other) { |
| message_ = other.message_; |
| message_payload_size_ = other.message_payload_size_; |
| data_ = other.data_; |
| size_ = other.size_; |
| cursor_ = other.cursor_; |
| other.Reset(); |
| return *this; |
| } |
| |
| size_t Buffer::Allocate(size_t num_bytes) { |
| const size_t aligned_num_bytes = Align(num_bytes); |
| const size_t new_cursor = cursor_ + aligned_num_bytes; |
| if (new_cursor < cursor_ || (new_cursor > size_ && !message_.is_valid())) { |
| // Either we've overflowed or exceeded a fixed capacity. |
| NOTREACHED(); |
| return 0; |
| } |
| |
| if (new_cursor > size_) { |
| // If we have an underlying message object we can extend its payload to |
| // obtain more storage capacity. |
| DCHECK_LE(message_payload_size_, new_cursor); |
| size_t additional_bytes = new_cursor - message_payload_size_; |
| DCHECK(base::IsValueInRangeForNumericType<uint32_t>(additional_bytes)); |
| uint32_t new_size; |
| MojoResult rv = MojoAppendMessageData( |
| message_.value(), static_cast<uint32_t>(additional_bytes), nullptr, 0, |
| nullptr, &data_, &new_size); |
| DCHECK_EQ(MOJO_RESULT_OK, rv); |
| message_payload_size_ = new_cursor; |
| size_ = new_size; |
| } |
| |
| DCHECK_LE(new_cursor, size_); |
| size_t block_start = cursor_; |
| cursor_ = new_cursor; |
| |
| // Ensure that all the allocated space is zeroed to avoid uninitialized bits |
| // leaking into messages. |
| // |
| // TODO(rockot): We should consider only clearing the alignment padding. This |
| // means being careful about generated bindings zeroing padding explicitly, |
| // which itself gets particularly messy with e.g. packed bool bitfields. |
| memset(static_cast<uint8_t*>(data_) + block_start, 0, aligned_num_bytes); |
| |
| return block_start; |
| } |
| |
| void Buffer::AttachHandles(std::vector<ScopedHandle>* handles) { |
| DCHECK(message_.is_valid()); |
| |
| uint32_t new_size = 0; |
| MojoResult rv = MojoAppendMessageData( |
| message_.value(), 0, reinterpret_cast<MojoHandle*>(handles->data()), |
| static_cast<uint32_t>(handles->size()), nullptr, &data_, &new_size); |
| if (rv != MOJO_RESULT_OK) |
| return; |
| |
| size_ = new_size; |
| for (auto& handle : *handles) |
| ignore_result(handle.release()); |
| } |
| |
| void Buffer::Seal() { |
| if (!message_.is_valid()) |
| return; |
| |
| // Ensure that the backing message has the final accumulated payload size. |
| DCHECK_LE(message_payload_size_, cursor_); |
| size_t additional_bytes = cursor_ - message_payload_size_; |
| DCHECK(base::IsValueInRangeForNumericType<uint32_t>(additional_bytes)); |
| |
| MojoAppendMessageDataOptions options; |
| options.struct_size = sizeof(options); |
| options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE; |
| void* data; |
| uint32_t size; |
| MojoResult rv = MojoAppendMessageData(message_.value(), |
| static_cast<uint32_t>(additional_bytes), |
| nullptr, 0, &options, &data, &size); |
| DCHECK_EQ(MOJO_RESULT_OK, rv); |
| message_ = MessageHandle(); |
| message_payload_size_ = cursor_; |
| data_ = data; |
| size_ = size; |
| } |
| |
| void Buffer::Reset() { |
| message_ = MessageHandle(); |
| data_ = nullptr; |
| size_ = 0; |
| cursor_ = 0; |
| } |
| |
| } // namespace internal |
| } // namespace mojo |