1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/public/cpp/bindings/lib/buffer.h"
6
7 #include "base/logging.h"
8 #include "base/numerics/safe_math.h"
9 #include "mojo/public/c/system/message_pipe.h"
10 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
11
12 namespace mojo {
13 namespace internal {
14
15 Buffer::Buffer() = default;
16
Buffer(void * data,size_t size,size_t cursor)17 Buffer::Buffer(void* data, size_t size, size_t cursor)
18 : data_(data), size_(size), cursor_(cursor) {
19 DCHECK(IsAligned(data_));
20 }
21
Buffer(MessageHandle message,size_t message_payload_size,void * data,size_t size)22 Buffer::Buffer(MessageHandle message,
23 size_t message_payload_size,
24 void* data,
25 size_t size)
26 : message_(message),
27 message_payload_size_(message_payload_size),
28 data_(data),
29 size_(size),
30 cursor_(0) {
31 DCHECK(IsAligned(data_));
32 }
33
Buffer(Buffer && other)34 Buffer::Buffer(Buffer&& other) {
35 *this = std::move(other);
36 }
37
38 Buffer::~Buffer() = default;
39
operator =(Buffer && other)40 Buffer& Buffer::operator=(Buffer&& other) {
41 message_ = other.message_;
42 message_payload_size_ = other.message_payload_size_;
43 data_ = other.data_;
44 size_ = other.size_;
45 cursor_ = other.cursor_;
46 other.Reset();
47 return *this;
48 }
49
Allocate(size_t num_bytes)50 size_t Buffer::Allocate(size_t num_bytes) {
51 const size_t aligned_num_bytes = Align(num_bytes);
52 const size_t new_cursor = cursor_ + aligned_num_bytes;
53 if (new_cursor < cursor_ || (new_cursor > size_ && !message_.is_valid())) {
54 // Either we've overflowed or exceeded a fixed capacity.
55 NOTREACHED();
56 return 0;
57 }
58
59 if (new_cursor > size_) {
60 // If we have an underlying message object we can extend its payload to
61 // obtain more storage capacity.
62 DCHECK_LE(message_payload_size_, new_cursor);
63 size_t additional_bytes = new_cursor - message_payload_size_;
64 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(additional_bytes));
65 uint32_t new_size;
66 MojoResult rv = MojoAppendMessageData(
67 message_.value(), static_cast<uint32_t>(additional_bytes), nullptr, 0,
68 nullptr, &data_, &new_size);
69 DCHECK_EQ(MOJO_RESULT_OK, rv);
70 message_payload_size_ = new_cursor;
71 size_ = new_size;
72 }
73
74 DCHECK_LE(new_cursor, size_);
75 size_t block_start = cursor_;
76 cursor_ = new_cursor;
77
78 // Ensure that all the allocated space is zeroed to avoid uninitialized bits
79 // leaking into messages.
80 //
81 // TODO(rockot): We should consider only clearing the alignment padding. This
82 // means being careful about generated bindings zeroing padding explicitly,
83 // which itself gets particularly messy with e.g. packed bool bitfields.
84 memset(static_cast<uint8_t*>(data_) + block_start, 0, aligned_num_bytes);
85
86 return block_start;
87 }
88
AttachHandles(std::vector<ScopedHandle> * handles)89 void Buffer::AttachHandles(std::vector<ScopedHandle>* handles) {
90 DCHECK(message_.is_valid());
91
92 uint32_t new_size = 0;
93 MojoResult rv = MojoAppendMessageData(
94 message_.value(), 0, reinterpret_cast<MojoHandle*>(handles->data()),
95 static_cast<uint32_t>(handles->size()), nullptr, &data_, &new_size);
96 if (rv != MOJO_RESULT_OK)
97 return;
98
99 size_ = new_size;
100 for (auto& handle : *handles)
101 ignore_result(handle.release());
102 }
103
Seal()104 void Buffer::Seal() {
105 if (!message_.is_valid())
106 return;
107
108 // Ensure that the backing message has the final accumulated payload size.
109 DCHECK_LE(message_payload_size_, cursor_);
110 size_t additional_bytes = cursor_ - message_payload_size_;
111 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(additional_bytes));
112
113 MojoAppendMessageDataOptions options;
114 options.struct_size = sizeof(options);
115 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
116 void* data;
117 uint32_t size;
118 MojoResult rv = MojoAppendMessageData(message_.value(),
119 static_cast<uint32_t>(additional_bytes),
120 nullptr, 0, &options, &data, &size);
121 DCHECK_EQ(MOJO_RESULT_OK, rv);
122 message_ = MessageHandle();
123 message_payload_size_ = cursor_;
124 data_ = data;
125 size_ = size;
126 }
127
Reset()128 void Buffer::Reset() {
129 message_ = MessageHandle();
130 data_ = nullptr;
131 size_ = 0;
132 cursor_ = 0;
133 }
134
135 } // namespace internal
136 } // namespace mojo
137