OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/system/message_in_transit.h" | 5 #include "mojo/system/message_in_transit.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include <new> | |
10 | |
11 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
12 #include "base/logging.h" | 10 #include "base/logging.h" |
13 #include "mojo/system/constants.h" | 11 #include "mojo/system/constants.h" |
| 12 #include "mojo/system/transport_data.h" |
14 | 13 |
15 namespace mojo { | 14 namespace mojo { |
16 namespace system { | 15 namespace system { |
17 | 16 |
18 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type | 17 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type |
19 MessageInTransit::kTypeMessagePipeEndpoint; | 18 MessageInTransit::kTypeMessagePipeEndpoint; |
20 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type | 19 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type |
21 MessageInTransit::kTypeMessagePipe; | 20 MessageInTransit::kTypeMessagePipe; |
22 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type | 21 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type |
23 MessageInTransit::kTypeChannel; | 22 MessageInTransit::kTypeChannel; |
24 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype | 23 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
25 MessageInTransit::kSubtypeMessagePipeEndpointData; | 24 MessageInTransit::kSubtypeMessagePipeEndpointData; |
26 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype | 25 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
27 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint; | 26 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint; |
28 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype | 27 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
29 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint; | 28 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint; |
30 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype | 29 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype |
31 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck; | 30 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck; |
32 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId | 31 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId |
33 MessageInTransit::kInvalidEndpointId; | 32 MessageInTransit::kInvalidEndpointId; |
34 STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment; | 33 STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment; |
35 STATIC_CONST_MEMBER_DEFINITION const size_t | |
36 MessageInTransit::kMaxSerializedDispatcherSize; | |
37 STATIC_CONST_MEMBER_DEFINITION const size_t | |
38 MessageInTransit::kMaxSerializedDispatcherPlatformHandles; | |
39 | 34 |
40 struct MessageInTransit::PrivateStructForCompileAsserts { | 35 struct MessageInTransit::PrivateStructForCompileAsserts { |
41 // The size of |Header| must be a multiple of the alignment. | 36 // The size of |Header| must be a multiple of the alignment. |
42 COMPILE_ASSERT(sizeof(Header) % kMessageAlignment == 0, | 37 COMPILE_ASSERT(sizeof(Header) % kMessageAlignment == 0, |
43 sizeof_MessageInTransit_Header_invalid); | 38 sizeof_MessageInTransit_Header_invalid); |
44 // Avoid dangerous situations, but making sure that the size of the "header" + | 39 // Avoid dangerous situations, but making sure that the size of the "header" + |
45 // the size of the data fits into a 31-bit number. | 40 // the size of the data fits into a 31-bit number. |
46 COMPILE_ASSERT(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <= | 41 COMPILE_ASSERT(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <= |
47 0x7fffffffULL, | 42 0x7fffffffULL, |
48 kMaxMessageNumBytes_too_big); | 43 kMaxMessageNumBytes_too_big); |
49 | 44 |
50 // We assume (to avoid extra rounding code) that the maximum message (data) | 45 // We assume (to avoid extra rounding code) that the maximum message (data) |
51 // size is a multiple of the alignment. | 46 // size is a multiple of the alignment. |
52 COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0, | 47 COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0, |
53 kMessageAlignment_not_a_multiple_of_alignment); | 48 kMessageAlignment_not_a_multiple_of_alignment); |
54 | |
55 // The maximum serialized dispatcher size must be a multiple of the alignment. | |
56 COMPILE_ASSERT(kMaxSerializedDispatcherSize % kMessageAlignment == 0, | |
57 kMaxSerializedDispatcherSize_not_a_multiple_of_alignment); | |
58 | |
59 // The size of |HandleTableEntry| must be a multiple of the alignment. | |
60 COMPILE_ASSERT(sizeof(HandleTableEntry) % kMessageAlignment == 0, | |
61 sizeof_MessageInTransit_HandleTableEntry_invalid); | |
62 }; | 49 }; |
63 | 50 |
64 // For each attached (Mojo) handle, there'll be a handle table entry and | |
65 // serialized dispatcher data. | |
66 // static | |
67 const size_t MessageInTransit::kMaxSecondaryBufferSize = kMaxMessageNumHandles * | |
68 (sizeof(HandleTableEntry) + kMaxSerializedDispatcherSize); | |
69 | |
70 // static | |
71 const size_t MessageInTransit::kMaxPlatformHandles = | |
72 kMaxMessageNumHandles * kMaxSerializedDispatcherPlatformHandles; | |
73 | |
74 MessageInTransit::View::View(size_t message_size, const void* buffer) | 51 MessageInTransit::View::View(size_t message_size, const void* buffer) |
75 : buffer_(buffer) { | 52 : buffer_(buffer) { |
76 size_t next_message_size = 0; | 53 size_t next_message_size = 0; |
77 DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size, | 54 DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size, |
78 &next_message_size)); | 55 &next_message_size)); |
79 DCHECK_EQ(message_size, next_message_size); | 56 DCHECK_EQ(message_size, next_message_size); |
80 // This should be equivalent. | 57 // This should be equivalent. |
81 DCHECK_EQ(message_size, total_size()); | 58 DCHECK_EQ(message_size, total_size()); |
82 } | 59 } |
83 | 60 |
84 bool MessageInTransit::View::IsValid(const char** error_message) const { | 61 bool MessageInTransit::View::IsValid(const char** error_message) const { |
85 // Note: This also implies a check on the |main_buffer_size()|, which is just | 62 // Note: This also implies a check on the |main_buffer_size()|, which is just |
86 // |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|. | 63 // |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|. |
87 if (num_bytes() > kMaxMessageNumBytes) { | 64 if (num_bytes() > kMaxMessageNumBytes) { |
88 *error_message = "Message data payload too large"; | 65 *error_message = "Message data payload too large"; |
89 return false; | 66 return false; |
90 } | 67 } |
91 | 68 |
92 if (const char* secondary_buffer_error_message = | 69 if (transport_data_buffer_size() > 0) { |
93 ValidateSecondaryBuffer(num_handles(), secondary_buffer(), | 70 const char* e = TransportData::ValidateBuffer(transport_data_buffer(), |
94 secondary_buffer_size())) { | 71 transport_data_buffer_size()); |
95 *error_message = secondary_buffer_error_message; | 72 if (e) { |
96 return false; | 73 *error_message = e; |
| 74 return false; |
| 75 } |
97 } | 76 } |
98 | 77 |
99 return true; | 78 return true; |
100 } | 79 } |
101 | 80 |
102 MessageInTransit::MessageInTransit(Type type, | 81 MessageInTransit::MessageInTransit(Type type, |
103 Subtype subtype, | 82 Subtype subtype, |
104 uint32_t num_bytes, | 83 uint32_t num_bytes, |
105 uint32_t num_handles, | |
106 const void* bytes) | 84 const void* bytes) |
107 : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)), | 85 : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)), |
108 main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, | 86 main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, |
109 kMessageAlignment))), | 87 kMessageAlignment))) { |
110 secondary_buffer_size_(0) { | |
111 DCHECK_LE(num_bytes, kMaxMessageNumBytes); | 88 DCHECK_LE(num_bytes, kMaxMessageNumBytes); |
112 DCHECK_LE(num_handles, kMaxMessageNumHandles); | |
113 | 89 |
114 // |total_size| is updated below, from the other values. | 90 // |total_size| is updated below, from the other values. |
115 header()->type = type; | 91 header()->type = type; |
116 header()->subtype = subtype; | 92 header()->subtype = subtype; |
117 header()->source_id = kInvalidEndpointId; | 93 header()->source_id = kInvalidEndpointId; |
118 header()->destination_id = kInvalidEndpointId; | 94 header()->destination_id = kInvalidEndpointId; |
119 header()->num_bytes = num_bytes; | 95 header()->num_bytes = num_bytes; |
120 header()->num_handles = num_handles; | 96 // Note: If dispatchers are subsequently attached, then |total_size| will have |
121 // Note: If dispatchers are subsequently attached (in particular, if | 97 // to be adjusted. |
122 // |num_handles| is nonzero), then |total_size| will have to be adjusted. | |
123 UpdateTotalSize(); | 98 UpdateTotalSize(); |
124 | 99 |
125 if (bytes) { | 100 if (bytes) { |
126 memcpy(MessageInTransit::bytes(), bytes, num_bytes); | 101 memcpy(MessageInTransit::bytes(), bytes, num_bytes); |
127 memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0, | 102 memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0, |
128 main_buffer_size_ - sizeof(Header) - num_bytes); | 103 main_buffer_size_ - sizeof(Header) - num_bytes); |
129 } else { | 104 } else { |
130 memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header)); | 105 memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header)); |
131 } | 106 } |
132 } | 107 } |
133 | 108 |
134 // TODO(vtl): Do I really want/need to copy the secondary buffer here, or should | |
135 // I just create (deserialize) the dispatchers right away? | |
136 MessageInTransit::MessageInTransit(const View& message_view) | 109 MessageInTransit::MessageInTransit(const View& message_view) |
137 : main_buffer_size_(message_view.main_buffer_size()), | 110 : main_buffer_size_(message_view.main_buffer_size()), |
138 main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, | 111 main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_, |
139 kMessageAlignment))), | 112 kMessageAlignment))) { |
140 secondary_buffer_size_(message_view.secondary_buffer_size()), | |
141 secondary_buffer_(secondary_buffer_size_ ? | |
142 static_cast<char*>( | |
143 base::AlignedAlloc(secondary_buffer_size_, | |
144 kMessageAlignment)) : NULL) { | |
145 DCHECK_GE(main_buffer_size_, sizeof(Header)); | 113 DCHECK_GE(main_buffer_size_, sizeof(Header)); |
146 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); | 114 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); |
147 | 115 |
148 memcpy(main_buffer_.get(), message_view.main_buffer(), main_buffer_size_); | 116 memcpy(main_buffer_.get(), message_view.main_buffer(), main_buffer_size_); |
149 memcpy(secondary_buffer_.get(), message_view.secondary_buffer(), | |
150 secondary_buffer_size_); | |
151 | |
152 DCHECK_EQ(main_buffer_size_, | 117 DCHECK_EQ(main_buffer_size_, |
153 RoundUpMessageAlignment(sizeof(Header) + num_bytes())); | 118 RoundUpMessageAlignment(sizeof(Header) + num_bytes())); |
154 } | 119 } |
155 | 120 |
156 MessageInTransit::~MessageInTransit() { | 121 MessageInTransit::~MessageInTransit() { |
157 if (dispatchers_) { | 122 if (dispatchers_) { |
158 for (size_t i = 0; i < dispatchers_->size(); i++) { | 123 for (size_t i = 0; i < dispatchers_->size(); i++) { |
159 if (!(*dispatchers_)[i]) | 124 if (!(*dispatchers_)[i]) |
160 continue; | 125 continue; |
161 | 126 |
162 DCHECK((*dispatchers_)[i]->HasOneRef()); | 127 DCHECK((*dispatchers_)[i]->HasOneRef()); |
163 (*dispatchers_)[i]->Close(); | 128 (*dispatchers_)[i]->Close(); |
164 } | 129 } |
165 } | 130 } |
166 | |
167 if (platform_handles_) { | |
168 for (size_t i = 0; i < platform_handles_->size(); i++) | |
169 (*platform_handles_)[i].CloseIfNecessary(); | |
170 } | |
171 | |
172 #ifndef NDEBUG | |
173 secondary_buffer_size_ = 0; | |
174 dispatchers_.reset(); | |
175 platform_handles_.reset(); | |
176 #endif | |
177 } | 131 } |
178 | 132 |
179 // static | 133 // static |
180 bool MessageInTransit::GetNextMessageSize(const void* buffer, | 134 bool MessageInTransit::GetNextMessageSize(const void* buffer, |
181 size_t buffer_size, | 135 size_t buffer_size, |
182 size_t* next_message_size) { | 136 size_t* next_message_size) { |
183 DCHECK(next_message_size); | 137 DCHECK(next_message_size); |
184 if (!buffer_size) | 138 if (!buffer_size) |
185 return false; | 139 return false; |
186 DCHECK(buffer); | 140 DCHECK(buffer); |
(...skipping 16 matching lines...) Expand all Loading... |
203 | 157 |
204 dispatchers_ = dispatchers.Pass(); | 158 dispatchers_ = dispatchers.Pass(); |
205 #ifndef NDEBUG | 159 #ifndef NDEBUG |
206 for (size_t i = 0; i < dispatchers_->size(); i++) | 160 for (size_t i = 0; i < dispatchers_->size(); i++) |
207 DCHECK(!(*dispatchers_)[i] || (*dispatchers_)[i]->HasOneRef()); | 161 DCHECK(!(*dispatchers_)[i] || (*dispatchers_)[i]->HasOneRef()); |
208 #endif | 162 #endif |
209 } | 163 } |
210 | 164 |
211 void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) { | 165 void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) { |
212 DCHECK(channel); | 166 DCHECK(channel); |
213 DCHECK(!secondary_buffer_); | 167 DCHECK(!transport_data_); |
214 | 168 |
215 const size_t num_handles = dispatchers_ ? dispatchers_->size() : 0; | 169 if (!dispatchers_ || !dispatchers_->size()) |
216 if (!num_handles) | |
217 return; | 170 return; |
218 | 171 |
219 // The offset to the start of the (Mojo) handle table. | 172 transport_data_.reset(new TransportData(dispatchers_.Pass(), channel)); |
220 // TODO(vtl): Add a header to the secondary buffer. | |
221 const size_t handle_table_start_offset = 0; | |
222 // The offset to the start of the serialized dispatcher data. | |
223 const size_t serialized_dispatcher_start_offset = | |
224 handle_table_start_offset + num_handles * sizeof(HandleTableEntry); | |
225 // The estimated size of the secondary buffer. We compute this estimate below. | |
226 // It must be at least as big as the (eventual) actual size. | |
227 size_t estimated_size = serialized_dispatcher_start_offset; | |
228 size_t num_platform_handles = 0; | |
229 #if DCHECK_IS_ON | |
230 std::vector<size_t> all_max_sizes(num_handles); | |
231 std::vector<size_t> all_max_platform_handles(num_handles); | |
232 #endif | |
233 for (size_t i = 0; i < num_handles; i++) { | |
234 if (Dispatcher* dispatcher = (*dispatchers_)[i].get()) { | |
235 size_t max_size = 0; | |
236 size_t max_platform_handles = 0; | |
237 Dispatcher::MessageInTransitAccess::StartSerialize( | |
238 dispatcher, channel, &max_size, &max_platform_handles); | |
239 | |
240 DCHECK_LE(max_size, kMaxSerializedDispatcherSize); | |
241 estimated_size += RoundUpMessageAlignment(max_size); | |
242 DCHECK_LE(estimated_size, kMaxSecondaryBufferSize); | |
243 | |
244 DCHECK_LE(max_platform_handles, | |
245 kMaxSerializedDispatcherPlatformHandles); | |
246 num_platform_handles += max_platform_handles; | |
247 DCHECK_LE(num_platform_handles, kMaxPlatformHandles); | |
248 | |
249 #if DCHECK_IS_ON | |
250 all_max_sizes[i] = max_size; | |
251 all_max_platform_handles[i] = max_platform_handles; | |
252 #endif | |
253 } | |
254 } | |
255 | |
256 secondary_buffer_.reset(static_cast<char*>( | |
257 base::AlignedAlloc(estimated_size, kMessageAlignment))); | |
258 // Entirely clear out the secondary buffer, since then we won't have to worry | |
259 // about clearing padding or unused space (e.g., if a dispatcher fails to | |
260 // serialize). | |
261 memset(secondary_buffer_.get(), 0, estimated_size); | |
262 | |
263 if (num_platform_handles > 0) { | |
264 DCHECK(!platform_handles_); | |
265 platform_handles_.reset(new std::vector<embedder::PlatformHandle>()); | |
266 } | |
267 | |
268 HandleTableEntry* handle_table = reinterpret_cast<HandleTableEntry*>( | |
269 secondary_buffer_.get() + handle_table_start_offset); | |
270 size_t current_offset = serialized_dispatcher_start_offset; | |
271 for (size_t i = 0; i < num_handles; i++) { | |
272 Dispatcher* dispatcher = (*dispatchers_)[i].get(); | |
273 if (!dispatcher) { | |
274 COMPILE_ASSERT(Dispatcher::kTypeUnknown == 0, | |
275 value_of_Dispatcher_kTypeUnknown_must_be_zero); | |
276 continue; | |
277 } | |
278 | |
279 #if DCHECK_IS_ON | |
280 size_t old_platform_handles_size = | |
281 platform_handles_ ? platform_handles_->size() : 0; | |
282 #endif | |
283 | |
284 void* destination = secondary_buffer_.get() + current_offset; | |
285 size_t actual_size = 0; | |
286 if (Dispatcher::MessageInTransitAccess::EndSerializeAndClose( | |
287 dispatcher, channel, destination, &actual_size, | |
288 platform_handles_.get())) { | |
289 handle_table[i].type = static_cast<int32_t>(dispatcher->GetType()); | |
290 handle_table[i].offset = static_cast<uint32_t>(current_offset); | |
291 handle_table[i].size = static_cast<uint32_t>(actual_size); | |
292 | |
293 #if DCHECK_IS_ON | |
294 DCHECK_LE(actual_size, all_max_sizes[i]); | |
295 DCHECK_LE(platform_handles_ ? (platform_handles_->size() - | |
296 old_platform_handles_size) : 0, | |
297 all_max_platform_handles[i]); | |
298 #endif | |
299 } else { | |
300 // Nothing to do on failure, since |secondary_buffer_| was cleared, and | |
301 // |kTypeUnknown| is zero. The handle was simply closed. | |
302 LOG(ERROR) << "Failed to serialize handle to remote message pipe"; | |
303 } | |
304 | |
305 current_offset += RoundUpMessageAlignment(actual_size); | |
306 DCHECK_LE(current_offset, estimated_size); | |
307 DCHECK_LE(platform_handles_ ? platform_handles_->size() : 0, | |
308 num_platform_handles); | |
309 } | |
310 | |
311 // There's no aligned realloc, so it's no good way to release unused space (if | |
312 // we overshot our estimated space requirements). | |
313 secondary_buffer_size_ = current_offset; | |
314 | |
315 // The dispatchers (which we "owned") were closed. We can dispose of them now. | |
316 dispatchers_.reset(); | |
317 | 173 |
318 // Update the sizes in the message header. | 174 // Update the sizes in the message header. |
319 UpdateTotalSize(); | 175 UpdateTotalSize(); |
320 } | 176 } |
321 | 177 |
322 // Note: The message's secondary buffer should have been checked by calling | 178 void MessageInTransit::UpdateTotalSize() { |
323 // |View::IsValid()| (on the |View|) first. | 179 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); |
324 void MessageInTransit::DeserializeDispatchers(Channel* channel) { | 180 header()->total_size = static_cast<uint32_t>(main_buffer_size_); |
325 DCHECK(!dispatchers_); | 181 if (transport_data_) { |
326 | 182 header()->total_size += |
327 // Already checked by |View::IsValid()|: | 183 static_cast<uint32_t>(transport_data_->buffer_size()); |
328 DCHECK_LE(num_handles(), kMaxMessageNumHandles); | |
329 | |
330 if (!num_handles()) | |
331 return; | |
332 | |
333 dispatchers_.reset( | |
334 new std::vector<scoped_refptr<Dispatcher> >(num_handles())); | |
335 | |
336 size_t handle_table_size = num_handles() * sizeof(HandleTableEntry); | |
337 // Already checked by |View::IsValid()|: | |
338 DCHECK_LE(handle_table_size, secondary_buffer_size_); | |
339 | |
340 const HandleTableEntry* handle_table = | |
341 reinterpret_cast<const HandleTableEntry*>(secondary_buffer_.get()); | |
342 for (size_t i = 0; i < num_handles(); i++) { | |
343 size_t offset = handle_table[i].offset; | |
344 size_t size = handle_table[i].size; | |
345 // Already checked by |View::IsValid()|: | |
346 DCHECK_EQ(offset % kMessageAlignment, 0u); | |
347 DCHECK_LE(offset, secondary_buffer_size_); | |
348 DCHECK_LE(offset + size, secondary_buffer_size_); | |
349 | |
350 const void* source = secondary_buffer_.get() + offset; | |
351 (*dispatchers_)[i] = Dispatcher::MessageInTransitAccess::Deserialize( | |
352 channel, handle_table[i].type, source, size); | |
353 } | 184 } |
354 } | 185 } |
355 | 186 |
356 // Validates the secondary buffer. Returns null on success, or a human-readable | |
357 // error message on error. | |
358 // static | |
359 const char* MessageInTransit::ValidateSecondaryBuffer( | |
360 size_t num_handles, | |
361 const void* secondary_buffer, | |
362 size_t secondary_buffer_size) { | |
363 // Always make sure that the secondary buffer size is sane (even if we have no | |
364 // handles); if it's not, someone's messing with us. | |
365 if (secondary_buffer_size > kMaxSecondaryBufferSize) | |
366 return "Message secondary buffer too large"; | |
367 | |
368 // Fast-path for the common case (no handles => no secondary buffer). | |
369 if (num_handles == 0) { | |
370 // We shouldn't have a secondary buffer in this case. | |
371 if (secondary_buffer_size > 0) | |
372 return "Message has no handles attached, but secondary buffer present"; | |
373 return NULL; | |
374 } | |
375 | |
376 // Sanity-check |num_handles| (before multiplying it against anything). | |
377 if (num_handles > kMaxMessageNumHandles) | |
378 return "Message handle payload too large"; | |
379 | |
380 if (secondary_buffer_size < num_handles * sizeof(HandleTableEntry)) | |
381 return "Message secondary buffer too small"; | |
382 | |
383 DCHECK(secondary_buffer); | |
384 const HandleTableEntry* handle_table = | |
385 static_cast<const HandleTableEntry*>(secondary_buffer); | |
386 | |
387 static const char kInvalidSerializedDispatcher[] = | |
388 "Message contains invalid serialized dispatcher"; | |
389 for (size_t i = 0; i < num_handles; i++) { | |
390 size_t offset = handle_table[i].offset; | |
391 if (offset % kMessageAlignment != 0) | |
392 return kInvalidSerializedDispatcher; | |
393 | |
394 size_t size = handle_table[i].size; | |
395 if (size > kMaxSerializedDispatcherSize || size > secondary_buffer_size) | |
396 return kInvalidSerializedDispatcher; | |
397 | |
398 // Note: This is an overflow-safe check for |offset + size > | |
399 // secondary_buffer_size()| (we know that |size <= secondary_buffer_size()| | |
400 // from the previous check). | |
401 if (offset > secondary_buffer_size - size) | |
402 return kInvalidSerializedDispatcher; | |
403 } | |
404 | |
405 return NULL; | |
406 } | |
407 | |
408 void MessageInTransit::UpdateTotalSize() { | |
409 DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u); | |
410 DCHECK_EQ(secondary_buffer_size_ % kMessageAlignment, 0u); | |
411 header()->total_size = | |
412 static_cast<uint32_t>(main_buffer_size_ + secondary_buffer_size_); | |
413 } | |
414 | |
415 } // namespace system | 187 } // namespace system |
416 } // namespace mojo | 188 } // namespace mojo |
OLD | NEW |