| 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 |