You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.0 KiB
137 lines
4.0 KiB
// 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
|