• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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