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 <algorithm>
6 #include <memory>
7 #include <utility>
8 #include <vector>
9
10 #include "base/memory/ptr_util.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/rand_util.h"
13 #include "build/build_config.h"
14 #include "mojo/core/test/mojo_test_base.h"
15 #include "mojo/core/user_message_impl.h"
16 #include "mojo/public/cpp/platform/platform_channel.h"
17 #include "mojo/public/cpp/system/buffer.h"
18 #include "mojo/public/cpp/system/message_pipe.h"
19 #include "mojo/public/cpp/system/platform_handle.h"
20
21 namespace mojo {
22 namespace core {
23 namespace {
24
25 using MessageTest = test::MojoTestBase;
26
27 // Helper class which provides a base implementation for an unserialized user
28 // message context and helpers to go between these objects and opaque message
29 // handles.
30 class TestMessageBase {
31 public:
~TestMessageBase()32 virtual ~TestMessageBase() {}
33
MakeMessageHandle(std::unique_ptr<TestMessageBase> message)34 static MojoMessageHandle MakeMessageHandle(
35 std::unique_ptr<TestMessageBase> message) {
36 MojoMessageHandle handle;
37 MojoResult rv = MojoCreateMessage(nullptr, &handle);
38 DCHECK_EQ(MOJO_RESULT_OK, rv);
39
40 rv = MojoSetMessageContext(
41 handle, reinterpret_cast<uintptr_t>(message.release()),
42 &TestMessageBase::SerializeMessageContext,
43 &TestMessageBase::DestroyMessageContext, nullptr);
44 DCHECK_EQ(MOJO_RESULT_OK, rv);
45
46 return handle;
47 }
48
49 template <typename T>
UnwrapMessageHandle(MojoMessageHandle * message_handle)50 static std::unique_ptr<T> UnwrapMessageHandle(
51 MojoMessageHandle* message_handle) {
52 MojoMessageHandle handle = MOJO_HANDLE_INVALID;
53 std::swap(handle, *message_handle);
54 uintptr_t context;
55 MojoResult rv = MojoGetMessageContext(handle, nullptr, &context);
56 DCHECK_EQ(MOJO_RESULT_OK, rv);
57 rv = MojoSetMessageContext(handle, 0, nullptr, nullptr, nullptr);
58 DCHECK_EQ(MOJO_RESULT_OK, rv);
59 MojoDestroyMessage(handle);
60 return base::WrapUnique(reinterpret_cast<T*>(context));
61 }
62
63 protected:
64 virtual void GetSerializedSize(size_t* num_bytes, size_t* num_handles) = 0;
65 virtual void SerializeHandles(MojoHandle* handles) = 0;
66 virtual void SerializePayload(void* buffer) = 0;
67
68 private:
SerializeMessageContext(MojoMessageHandle message_handle,uintptr_t context)69 static void SerializeMessageContext(MojoMessageHandle message_handle,
70 uintptr_t context) {
71 auto* message = reinterpret_cast<TestMessageBase*>(context);
72 size_t num_bytes = 0;
73 size_t num_handles = 0;
74 message->GetSerializedSize(&num_bytes, &num_handles);
75 std::vector<MojoHandle> handles(num_handles);
76 if (num_handles)
77 message->SerializeHandles(handles.data());
78
79 MojoAppendMessageDataOptions options;
80 options.struct_size = sizeof(options);
81 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
82 void* buffer;
83 uint32_t buffer_size;
84 MojoResult rv = MojoAppendMessageData(
85 message_handle, base::checked_cast<uint32_t>(num_bytes), handles.data(),
86 base::checked_cast<uint32_t>(num_handles), &options, &buffer,
87 &buffer_size);
88 DCHECK_EQ(MOJO_RESULT_OK, rv);
89 DCHECK_GE(buffer_size, base::checked_cast<uint32_t>(num_bytes));
90 if (num_bytes)
91 message->SerializePayload(buffer);
92 }
93
DestroyMessageContext(uintptr_t context)94 static void DestroyMessageContext(uintptr_t context) {
95 delete reinterpret_cast<TestMessageBase*>(context);
96 }
97 };
98
99 class NeverSerializedMessage : public TestMessageBase {
100 public:
NeverSerializedMessage(const base::Closure & destruction_callback=base::Closure ())101 NeverSerializedMessage(
102 const base::Closure& destruction_callback = base::Closure())
103 : destruction_callback_(destruction_callback) {}
~NeverSerializedMessage()104 ~NeverSerializedMessage() override {
105 if (destruction_callback_)
106 destruction_callback_.Run();
107 }
108
109 private:
110 // TestMessageBase:
GetSerializedSize(size_t * num_bytes,size_t * num_handles)111 void GetSerializedSize(size_t* num_bytes, size_t* num_handles) override {
112 NOTREACHED();
113 }
SerializeHandles(MojoHandle * handles)114 void SerializeHandles(MojoHandle* handles) override { NOTREACHED(); }
SerializePayload(void * buffer)115 void SerializePayload(void* buffer) override { NOTREACHED(); }
116
117 const base::Closure destruction_callback_;
118
119 DISALLOW_COPY_AND_ASSIGN(NeverSerializedMessage);
120 };
121
122 class SimpleMessage : public TestMessageBase {
123 public:
SimpleMessage(const std::string & contents,const base::Closure & destruction_callback=base::Closure ())124 SimpleMessage(const std::string& contents,
125 const base::Closure& destruction_callback = base::Closure())
126 : contents_(contents), destruction_callback_(destruction_callback) {}
127
~SimpleMessage()128 ~SimpleMessage() override {
129 if (destruction_callback_)
130 destruction_callback_.Run();
131 }
132
AddMessagePipe(mojo::ScopedMessagePipeHandle handle)133 void AddMessagePipe(mojo::ScopedMessagePipeHandle handle) {
134 handles_.emplace_back(std::move(handle));
135 }
136
handles()137 std::vector<mojo::ScopedMessagePipeHandle>& handles() { return handles_; }
138
139 private:
140 // TestMessageBase:
GetSerializedSize(size_t * num_bytes,size_t * num_handles)141 void GetSerializedSize(size_t* num_bytes, size_t* num_handles) override {
142 *num_bytes = contents_.size();
143 *num_handles = handles_.size();
144 }
145
SerializeHandles(MojoHandle * handles)146 void SerializeHandles(MojoHandle* handles) override {
147 ASSERT_TRUE(!handles_.empty());
148 for (size_t i = 0; i < handles_.size(); ++i)
149 handles[i] = handles_[i].release().value();
150 handles_.clear();
151 }
152
SerializePayload(void * buffer)153 void SerializePayload(void* buffer) override {
154 std::copy(contents_.begin(), contents_.end(), static_cast<char*>(buffer));
155 }
156
157 const std::string contents_;
158 const base::Closure destruction_callback_;
159 std::vector<mojo::ScopedMessagePipeHandle> handles_;
160
161 DISALLOW_COPY_AND_ASSIGN(SimpleMessage);
162 };
163
TEST_F(MessageTest,InvalidMessageObjects)164 TEST_F(MessageTest, InvalidMessageObjects) {
165 ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
166 MojoDestroyMessage(MOJO_MESSAGE_HANDLE_INVALID));
167
168 ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
169 MojoAppendMessageData(MOJO_MESSAGE_HANDLE_INVALID, 0, nullptr, 0,
170 nullptr, nullptr, nullptr));
171
172 ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
173 MojoGetMessageData(MOJO_MESSAGE_HANDLE_INVALID, nullptr, nullptr,
174 nullptr, nullptr, nullptr));
175
176 ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
177 MojoSerializeMessage(MOJO_MESSAGE_HANDLE_INVALID, nullptr));
178
179 MojoMessageHandle message_handle;
180 ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCreateMessage(nullptr, nullptr));
181 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message_handle));
182 ASSERT_EQ(MOJO_RESULT_OK, MojoSetMessageContext(message_handle, 0, nullptr,
183 nullptr, nullptr));
184 ASSERT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
185 }
186
TEST_F(MessageTest,SendLocalMessageWithContext)187 TEST_F(MessageTest, SendLocalMessageWithContext) {
188 // Simple write+read of a message with context. Verifies that such messages
189 // are passed through a local pipe without serialization.
190 auto message = std::make_unique<NeverSerializedMessage>();
191 auto* original_message = message.get();
192
193 MojoHandle a, b;
194 CreateMessagePipe(&a, &b);
195 EXPECT_EQ(
196 MOJO_RESULT_OK,
197 MojoWriteMessage(
198 a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr));
199 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE));
200
201 MojoMessageHandle read_message_handle;
202 EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &read_message_handle));
203 message = TestMessageBase::UnwrapMessageHandle<NeverSerializedMessage>(
204 &read_message_handle);
205 EXPECT_EQ(original_message, message.get());
206
207 MojoClose(a);
208 MojoClose(b);
209 }
210
TEST_F(MessageTest,DestroyMessageWithContext)211 TEST_F(MessageTest, DestroyMessageWithContext) {
212 // Tests that |MojoDestroyMessage()| destroys any attached context.
213 bool was_deleted = false;
214 auto message = std::make_unique<NeverSerializedMessage>(
215 base::Bind([](bool* was_deleted) { *was_deleted = true; }, &was_deleted));
216 MojoMessageHandle handle =
217 TestMessageBase::MakeMessageHandle(std::move(message));
218 EXPECT_FALSE(was_deleted);
219 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(handle));
220 EXPECT_TRUE(was_deleted);
221 }
222
223 const char kTestMessageWithContext1[] = "hello laziness";
224
225 #if !defined(OS_IOS)
226
227 const char kTestMessageWithContext2[] = "my old friend";
228 const char kTestMessageWithContext3[] = "something something";
229 const char kTestMessageWithContext4[] = "do moar ipc";
230
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveMessageNoHandles,MessageTest,h)231 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveMessageNoHandles, MessageTest, h) {
232 MojoTestBase::WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE);
233 auto m = MojoTestBase::ReadMessage(h);
234 EXPECT_EQ(kTestMessageWithContext1, m);
235 }
236
TEST_F(MessageTest,SerializeSimpleMessageNoHandlesWithContext)237 TEST_F(MessageTest, SerializeSimpleMessageNoHandlesWithContext) {
238 RunTestClient("ReceiveMessageNoHandles", [&](MojoHandle h) {
239 auto message = std::make_unique<SimpleMessage>(kTestMessageWithContext1);
240 MojoWriteMessage(h, TestMessageBase::MakeMessageHandle(std::move(message)),
241 nullptr);
242 });
243 }
244
TEST_F(MessageTest,SerializeDynamicallySizedMessage)245 TEST_F(MessageTest, SerializeDynamicallySizedMessage) {
246 RunTestClient("ReceiveMessageNoHandles", [&](MojoHandle h) {
247 MojoMessageHandle message;
248 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
249
250 void* buffer;
251 uint32_t buffer_size;
252 EXPECT_EQ(MOJO_RESULT_OK,
253 MojoAppendMessageData(message, 0, nullptr, 0, nullptr, &buffer,
254 &buffer_size));
255
256 MojoAppendMessageDataOptions options;
257 options.struct_size = sizeof(options);
258 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
259 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(
260 message, sizeof(kTestMessageWithContext1) - 1,
261 nullptr, 0, &options, &buffer, &buffer_size));
262
263 memcpy(buffer, kTestMessageWithContext1,
264 sizeof(kTestMessageWithContext1) - 1);
265 MojoWriteMessage(h, message, nullptr);
266 });
267 }
268
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveMessageOneHandle,MessageTest,h)269 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveMessageOneHandle, MessageTest, h) {
270 MojoTestBase::WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE);
271 MojoHandle h1;
272 auto m = MojoTestBase::ReadMessageWithHandles(h, &h1, 1);
273 EXPECT_EQ(kTestMessageWithContext1, m);
274 MojoTestBase::WriteMessage(h1, kTestMessageWithContext2);
275 }
276
TEST_F(MessageTest,SerializeSimpleMessageOneHandleWithContext)277 TEST_F(MessageTest, SerializeSimpleMessageOneHandleWithContext) {
278 RunTestClient("ReceiveMessageOneHandle", [&](MojoHandle h) {
279 auto message = std::make_unique<SimpleMessage>(kTestMessageWithContext1);
280 mojo::MessagePipe pipe;
281 message->AddMessagePipe(std::move(pipe.handle0));
282 MojoWriteMessage(h, TestMessageBase::MakeMessageHandle(std::move(message)),
283 nullptr);
284 EXPECT_EQ(kTestMessageWithContext2,
285 MojoTestBase::ReadMessage(pipe.handle1.get().value()));
286 });
287 }
288
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveMessageWithHandles,MessageTest,h)289 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveMessageWithHandles, MessageTest, h) {
290 MojoTestBase::WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE);
291 MojoHandle handles[4];
292 auto m = MojoTestBase::ReadMessageWithHandles(h, handles, 4);
293 EXPECT_EQ(kTestMessageWithContext1, m);
294 MojoTestBase::WriteMessage(handles[0], kTestMessageWithContext1);
295 MojoTestBase::WriteMessage(handles[1], kTestMessageWithContext2);
296 MojoTestBase::WriteMessage(handles[2], kTestMessageWithContext3);
297 MojoTestBase::WriteMessage(handles[3], kTestMessageWithContext4);
298 }
299
TEST_F(MessageTest,SerializeSimpleMessageWithHandlesWithContext)300 TEST_F(MessageTest, SerializeSimpleMessageWithHandlesWithContext) {
301 RunTestClient("ReceiveMessageWithHandles", [&](MojoHandle h) {
302 auto message = std::make_unique<SimpleMessage>(kTestMessageWithContext1);
303 mojo::MessagePipe pipes[4];
304 message->AddMessagePipe(std::move(pipes[0].handle0));
305 message->AddMessagePipe(std::move(pipes[1].handle0));
306 message->AddMessagePipe(std::move(pipes[2].handle0));
307 message->AddMessagePipe(std::move(pipes[3].handle0));
308 MojoWriteMessage(h, TestMessageBase::MakeMessageHandle(std::move(message)),
309 nullptr);
310 EXPECT_EQ(kTestMessageWithContext1,
311 MojoTestBase::ReadMessage(pipes[0].handle1.get().value()));
312 EXPECT_EQ(kTestMessageWithContext2,
313 MojoTestBase::ReadMessage(pipes[1].handle1.get().value()));
314 EXPECT_EQ(kTestMessageWithContext3,
315 MojoTestBase::ReadMessage(pipes[2].handle1.get().value()));
316 EXPECT_EQ(kTestMessageWithContext4,
317 MojoTestBase::ReadMessage(pipes[3].handle1.get().value()));
318 });
319 }
320
321 #endif // !defined(OS_IOS)
322
TEST_F(MessageTest,SendLocalSimpleMessageWithHandlesWithContext)323 TEST_F(MessageTest, SendLocalSimpleMessageWithHandlesWithContext) {
324 auto message = std::make_unique<SimpleMessage>(kTestMessageWithContext1);
325 auto* original_message = message.get();
326 mojo::MessagePipe pipes[4];
327 MojoHandle original_handles[4] = {
328 pipes[0].handle0.get().value(), pipes[1].handle0.get().value(),
329 pipes[2].handle0.get().value(), pipes[3].handle0.get().value(),
330 };
331 message->AddMessagePipe(std::move(pipes[0].handle0));
332 message->AddMessagePipe(std::move(pipes[1].handle0));
333 message->AddMessagePipe(std::move(pipes[2].handle0));
334 message->AddMessagePipe(std::move(pipes[3].handle0));
335
336 MojoHandle a, b;
337 CreateMessagePipe(&a, &b);
338 EXPECT_EQ(
339 MOJO_RESULT_OK,
340 MojoWriteMessage(
341 a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr));
342 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE));
343
344 MojoMessageHandle read_message_handle;
345 EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &read_message_handle));
346 message =
347 TestMessageBase::UnwrapMessageHandle<SimpleMessage>(&read_message_handle);
348 EXPECT_EQ(original_message, message.get());
349 ASSERT_EQ(4u, message->handles().size());
350 EXPECT_EQ(original_handles[0], message->handles()[0].get().value());
351 EXPECT_EQ(original_handles[1], message->handles()[1].get().value());
352 EXPECT_EQ(original_handles[2], message->handles()[2].get().value());
353 EXPECT_EQ(original_handles[3], message->handles()[3].get().value());
354
355 MojoClose(a);
356 MojoClose(b);
357 }
358
TEST_F(MessageTest,DropUnreadLocalMessageWithContext)359 TEST_F(MessageTest, DropUnreadLocalMessageWithContext) {
360 // Verifies that if a message is sent with context over a pipe and the
361 // receiver closes without reading the message, the context is properly
362 // cleaned up.
363 bool message_was_destroyed = false;
364 auto message = std::make_unique<SimpleMessage>(
365 kTestMessageWithContext1,
366 base::Bind([](bool* was_destroyed) { *was_destroyed = true; },
367 &message_was_destroyed));
368
369 mojo::MessagePipe pipe;
370 message->AddMessagePipe(std::move(pipe.handle0));
371 MojoHandle a, b;
372 CreateMessagePipe(&a, &b);
373 EXPECT_EQ(
374 MOJO_RESULT_OK,
375 MojoWriteMessage(
376 a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr));
377 MojoClose(a);
378 MojoClose(b);
379
380 EXPECT_TRUE(message_was_destroyed);
381 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(pipe.handle1.get().value(),
382 MOJO_HANDLE_SIGNAL_PEER_CLOSED));
383 }
384
TEST_F(MessageTest,GetMessageDataWithHandles)385 TEST_F(MessageTest, GetMessageDataWithHandles) {
386 MojoHandle h[2];
387 CreateMessagePipe(&h[0], &h[1]);
388
389 MojoMessageHandle message_handle;
390 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message_handle));
391
392 MojoAppendMessageDataOptions append_data_options;
393 append_data_options.struct_size = sizeof(append_data_options);
394 append_data_options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
395 const std::string kTestMessage = "hello";
396 void* buffer;
397 uint32_t buffer_size;
398 ASSERT_EQ(MOJO_RESULT_OK,
399 MojoAppendMessageData(
400 message_handle, static_cast<uint32_t>(kTestMessage.size()), h,
401 2, &append_data_options, &buffer, &buffer_size));
402 memcpy(buffer, kTestMessage.data(), kTestMessage.size());
403
404 // Ignore handles the first time around. This should mean a subsequent call is
405 // allowed to grab the handles.
406 MojoGetMessageDataOptions get_data_options;
407 get_data_options.struct_size = sizeof(get_data_options);
408 get_data_options.flags = MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES;
409 EXPECT_EQ(MOJO_RESULT_OK,
410 MojoGetMessageData(message_handle, &get_data_options, &buffer,
411 &buffer_size, nullptr, nullptr));
412
413 // Now grab the handles.
414 uint32_t num_handles = 2;
415 EXPECT_EQ(MOJO_RESULT_OK, MojoGetMessageData(message_handle, nullptr, &buffer,
416 &buffer_size, h, &num_handles));
417 EXPECT_EQ(2u, num_handles);
418
419 // Should still be callable as long as we ignore handles.
420 EXPECT_EQ(MOJO_RESULT_OK,
421 MojoGetMessageData(message_handle, &get_data_options, &buffer,
422 &buffer_size, nullptr, nullptr));
423
424 // But not if we don't.
425 EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
426 MojoGetMessageData(message_handle, nullptr, &buffer, &buffer_size,
427 h, &num_handles));
428
429 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
430 }
431
TEST_F(MessageTest,ReadMessageWithContextAsSerializedMessage)432 TEST_F(MessageTest, ReadMessageWithContextAsSerializedMessage) {
433 bool message_was_destroyed = false;
434 std::unique_ptr<TestMessageBase> message =
435 std::make_unique<NeverSerializedMessage>(
436 base::Bind([](bool* was_destroyed) { *was_destroyed = true; },
437 &message_was_destroyed));
438
439 MojoHandle a, b;
440 CreateMessagePipe(&a, &b);
441 EXPECT_EQ(
442 MOJO_RESULT_OK,
443 MojoWriteMessage(
444 a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr));
445 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE));
446
447 MojoMessageHandle message_handle;
448 EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &message_handle));
449 EXPECT_FALSE(message_was_destroyed);
450
451 // Not a serialized message, so we can't get serialized contents.
452 uint32_t num_bytes = 0;
453 void* buffer;
454 uint32_t num_handles = 0;
455 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
456 MojoGetMessageData(message_handle, nullptr, &buffer, &num_bytes,
457 nullptr, &num_handles));
458 EXPECT_FALSE(message_was_destroyed);
459
460 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
461 EXPECT_TRUE(message_was_destroyed);
462
463 MojoClose(a);
464 MojoClose(b);
465 }
466
TEST_F(MessageTest,ReadSerializedMessageAsMessageWithContext)467 TEST_F(MessageTest, ReadSerializedMessageAsMessageWithContext) {
468 MojoHandle a, b;
469 CreateMessagePipe(&a, &b);
470 MojoTestBase::WriteMessage(a, "hello there");
471 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE));
472
473 MojoMessageHandle message_handle;
474 EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &message_handle));
475 uintptr_t context;
476 EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
477 MojoGetMessageContext(message_handle, nullptr, &context));
478 MojoClose(a);
479 MojoClose(b);
480 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
481 }
482
TEST_F(MessageTest,ForceSerializeMessageWithContext)483 TEST_F(MessageTest, ForceSerializeMessageWithContext) {
484 // Basic test - we can serialize a simple message.
485 bool message_was_destroyed = false;
486 auto message = std::make_unique<SimpleMessage>(
487 kTestMessageWithContext1,
488 base::Bind([](bool* was_destroyed) { *was_destroyed = true; },
489 &message_was_destroyed));
490 auto message_handle = TestMessageBase::MakeMessageHandle(std::move(message));
491 EXPECT_EQ(MOJO_RESULT_OK, MojoSerializeMessage(message_handle, nullptr));
492 EXPECT_TRUE(message_was_destroyed);
493 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
494
495 // Serialize a message with a single handle. Freeing the message should close
496 // the handle.
497 message_was_destroyed = false;
498 message = std::make_unique<SimpleMessage>(
499 kTestMessageWithContext1,
500 base::Bind([](bool* was_destroyed) { *was_destroyed = true; },
501 &message_was_destroyed));
502 MessagePipe pipe1;
503 message->AddMessagePipe(std::move(pipe1.handle0));
504 message_handle = TestMessageBase::MakeMessageHandle(std::move(message));
505 EXPECT_EQ(MOJO_RESULT_OK, MojoSerializeMessage(message_handle, nullptr));
506 EXPECT_TRUE(message_was_destroyed);
507 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
508 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(pipe1.handle1.get().value(),
509 MOJO_HANDLE_SIGNAL_PEER_CLOSED));
510
511 // Serialize a message with a handle and extract its serialized contents.
512 message_was_destroyed = false;
513 message = std::make_unique<SimpleMessage>(
514 kTestMessageWithContext1,
515 base::Bind([](bool* was_destroyed) { *was_destroyed = true; },
516 &message_was_destroyed));
517 MessagePipe pipe2;
518 message->AddMessagePipe(std::move(pipe2.handle0));
519 message_handle = TestMessageBase::MakeMessageHandle(std::move(message));
520 EXPECT_EQ(MOJO_RESULT_OK, MojoSerializeMessage(message_handle, nullptr));
521 EXPECT_TRUE(message_was_destroyed);
522 uint32_t num_bytes = 0;
523 void* buffer = nullptr;
524 uint32_t num_handles = 0;
525 MojoHandle extracted_handle;
526 EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
527 MojoGetMessageData(message_handle, nullptr, &buffer, &num_bytes,
528 nullptr, &num_handles));
529 EXPECT_EQ(MOJO_RESULT_OK,
530 MojoGetMessageData(message_handle, nullptr, &buffer, &num_bytes,
531 &extracted_handle, &num_handles));
532 EXPECT_EQ(std::string(kTestMessageWithContext1).size(), num_bytes);
533 EXPECT_EQ(std::string(kTestMessageWithContext1),
534 base::StringPiece(static_cast<char*>(buffer), num_bytes));
535
536 // Confirm that the handle we extracted from the serialized message is still
537 // connected to the same peer, despite the fact that its handle value may have
538 // changed.
539 const char kTestMessage[] = "hey you";
540 MojoTestBase::WriteMessage(pipe2.handle1.get().value(), kTestMessage);
541 EXPECT_EQ(MOJO_RESULT_OK,
542 WaitForSignals(extracted_handle, MOJO_HANDLE_SIGNAL_READABLE));
543 EXPECT_EQ(kTestMessage, MojoTestBase::ReadMessage(extracted_handle));
544
545 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
546 }
547
TEST_F(MessageTest,DoubleSerialize)548 TEST_F(MessageTest, DoubleSerialize) {
549 bool message_was_destroyed = false;
550 auto message = std::make_unique<SimpleMessage>(
551 kTestMessageWithContext1,
552 base::Bind([](bool* was_destroyed) { *was_destroyed = true; },
553 &message_was_destroyed));
554 auto message_handle = TestMessageBase::MakeMessageHandle(std::move(message));
555
556 // Ensure we can safely call |MojoSerializeMessage()| twice on the same
557 // message handle.
558 EXPECT_EQ(MOJO_RESULT_OK, MojoSerializeMessage(message_handle, nullptr));
559 EXPECT_TRUE(message_was_destroyed);
560 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
561 MojoSerializeMessage(message_handle, nullptr));
562
563 // And also check that we can call it again after we've written and read the
564 // message object from a pipe.
565 MessagePipe pipe;
566 EXPECT_EQ(MOJO_RESULT_OK,
567 MojoWriteMessage(pipe.handle0->value(), message_handle, nullptr));
568 EXPECT_EQ(MOJO_RESULT_OK,
569 WaitForSignals(pipe.handle1->value(), MOJO_HANDLE_SIGNAL_READABLE));
570 EXPECT_EQ(MOJO_RESULT_OK,
571 MojoReadMessage(pipe.handle1->value(), nullptr, &message_handle));
572 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
573 MojoSerializeMessage(message_handle, nullptr));
574
575 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
576 }
577
TEST_F(MessageTest,ExtendMessagePayload)578 TEST_F(MessageTest, ExtendMessagePayload) {
579 MojoMessageHandle message;
580 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
581
582 const std::string kTestMessagePart1("hello i am message.");
583 void* buffer;
584 uint32_t buffer_size;
585 EXPECT_EQ(MOJO_RESULT_OK,
586 MojoAppendMessageData(
587 message, static_cast<uint32_t>(kTestMessagePart1.size()),
588 nullptr, 0, nullptr, &buffer, &buffer_size));
589 ASSERT_GE(buffer_size, static_cast<uint32_t>(kTestMessagePart1.size()));
590 memcpy(buffer, kTestMessagePart1.data(), kTestMessagePart1.size());
591
592 const std::string kTestMessagePart2 = " in ur computer.";
593 const std::string kTestMessageCombined1 =
594 kTestMessagePart1 + kTestMessagePart2;
595 EXPECT_EQ(MOJO_RESULT_OK,
596 MojoAppendMessageData(
597 message, static_cast<uint32_t>(kTestMessagePart2.size()),
598 nullptr, 0, nullptr, &buffer, &buffer_size));
599 memcpy(static_cast<uint8_t*>(buffer) + kTestMessagePart1.size(),
600 kTestMessagePart2.data(), kTestMessagePart2.size());
601
602 const std::string kTestMessagePart3 = kTestMessagePart2 + " carry ur bits.";
603 const std::string kTestMessageCombined2 =
604 kTestMessageCombined1 + kTestMessagePart3;
605 EXPECT_EQ(MOJO_RESULT_OK,
606 MojoAppendMessageData(
607 message, static_cast<uint32_t>(kTestMessagePart3.size()),
608 nullptr, 0, nullptr, &buffer, &buffer_size));
609 memcpy(static_cast<uint8_t*>(buffer) + kTestMessageCombined1.size(),
610 kTestMessagePart3.data(), kTestMessagePart3.size());
611
612 void* payload;
613 uint32_t payload_size;
614 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
615 MojoGetMessageData(message, nullptr, &payload, &payload_size,
616 nullptr, nullptr));
617
618 MojoAppendMessageDataOptions options;
619 options.struct_size = sizeof(options);
620 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
621 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, nullptr, 0,
622 &options, nullptr, nullptr));
623
624 EXPECT_EQ(MOJO_RESULT_OK,
625 MojoGetMessageData(message, nullptr, &payload, &payload_size,
626 nullptr, nullptr));
627 EXPECT_EQ(kTestMessageCombined2.size(), payload_size);
628 EXPECT_EQ(0, memcmp(payload, kTestMessageCombined2.data(),
629 kTestMessageCombined2.size()));
630
631 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
632 }
633
TEST_F(MessageTest,ExtendMessageWithHandlesPayload)634 TEST_F(MessageTest, ExtendMessageWithHandlesPayload) {
635 MojoMessageHandle message;
636 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
637
638 MojoHandle handles[2];
639 CreateMessagePipe(&handles[0], &handles[1]);
640
641 const std::string kTestMessagePart1("hello i am message.");
642 void* buffer;
643 uint32_t buffer_size;
644 EXPECT_EQ(MOJO_RESULT_OK,
645 MojoAppendMessageData(
646 message, static_cast<uint32_t>(kTestMessagePart1.size()),
647 handles, 2, nullptr, &buffer, &buffer_size));
648 ASSERT_GE(buffer_size, static_cast<uint32_t>(kTestMessagePart1.size()));
649 memcpy(buffer, kTestMessagePart1.data(), kTestMessagePart1.size());
650
651 const std::string kTestMessagePart2 = " in ur computer.";
652 const std::string kTestMessageCombined1 =
653 kTestMessagePart1 + kTestMessagePart2;
654 MojoAppendMessageDataOptions options;
655 options.struct_size = sizeof(options);
656 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
657 EXPECT_EQ(MOJO_RESULT_OK,
658 MojoAppendMessageData(
659 message, static_cast<uint32_t>(kTestMessagePart2.size()),
660 nullptr, 0, &options, &buffer, &buffer_size));
661 memcpy(static_cast<uint8_t*>(buffer) + kTestMessagePart1.size(),
662 kTestMessagePart2.data(), kTestMessagePart2.size());
663
664 void* payload;
665 uint32_t payload_size;
666 uint32_t num_handles = 2;
667 EXPECT_EQ(MOJO_RESULT_OK,
668 MojoGetMessageData(message, nullptr, &payload, &payload_size,
669 handles, &num_handles));
670 EXPECT_EQ(2u, num_handles);
671 EXPECT_EQ(kTestMessageCombined1.size(), payload_size);
672 EXPECT_EQ(0, memcmp(payload, kTestMessageCombined1.data(),
673 kTestMessageCombined1.size()));
674
675 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[0]));
676 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[1]));
677 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
678 }
679
TEST_F(MessageTest,ExtendMessagePayloadLarge)680 TEST_F(MessageTest, ExtendMessagePayloadLarge) {
681 // We progressively extend a message payload from small to large using various
682 // chunk sizes to test potentially interesting boundary conditions.
683 constexpr size_t kTestChunkSizes[] = {1, 2, 3, 64, 509, 4096, 16384, 65535};
684 for (const size_t kChunkSize : kTestChunkSizes) {
685 MojoMessageHandle message;
686 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
687
688 MojoHandle handles[2];
689 CreateMessagePipe(&handles[0], &handles[1]);
690
691 const std::string kTestMessageHeader("hey pretend i'm a header");
692 void* buffer;
693 uint32_t buffer_size;
694 EXPECT_EQ(MOJO_RESULT_OK,
695 MojoAppendMessageData(
696 message, static_cast<uint32_t>(kTestMessageHeader.size()),
697 handles, 2, nullptr, &buffer, &buffer_size));
698 ASSERT_GE(buffer_size, static_cast<uint32_t>(kTestMessageHeader.size()));
699 memcpy(buffer, kTestMessageHeader.data(), kTestMessageHeader.size());
700
701 // 512 kB should be well beyond any reasonable default buffer size for the
702 // system implementation to choose, meaning that this test should guarantee
703 // several reallocations of the serialized message buffer as we
704 // progressively extend the payload to this size.
705 constexpr size_t kTestMessagePayloadSize = 512 * 1024;
706 std::vector<uint8_t> test_payload(kTestMessagePayloadSize);
707 base::RandBytes(test_payload.data(), kTestMessagePayloadSize);
708
709 size_t current_payload_size = 0;
710 while (current_payload_size < kTestMessagePayloadSize) {
711 const size_t previous_payload_size = current_payload_size;
712 current_payload_size =
713 std::min(current_payload_size + kChunkSize, kTestMessagePayloadSize);
714 const size_t current_chunk_size =
715 current_payload_size - previous_payload_size;
716 const size_t previous_total_size =
717 kTestMessageHeader.size() + previous_payload_size;
718 const size_t current_total_size =
719 kTestMessageHeader.size() + current_payload_size;
720 EXPECT_EQ(MOJO_RESULT_OK,
721 MojoAppendMessageData(
722 message, static_cast<uint32_t>(current_chunk_size), nullptr,
723 0, nullptr, &buffer, &buffer_size));
724 EXPECT_GE(buffer_size, static_cast<uint32_t>(current_total_size));
725 memcpy(static_cast<uint8_t*>(buffer) + previous_total_size,
726 &test_payload[previous_payload_size], current_chunk_size);
727 }
728
729 MojoAppendMessageDataOptions options;
730 options.struct_size = sizeof(options);
731 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
732 EXPECT_EQ(MOJO_RESULT_OK,
733 MojoAppendMessageData(message, 0, nullptr, 0, &options, nullptr,
734 nullptr));
735
736 void* payload;
737 uint32_t payload_size;
738 uint32_t num_handles = 2;
739 EXPECT_EQ(MOJO_RESULT_OK,
740 MojoGetMessageData(message, nullptr, &payload, &payload_size,
741 handles, &num_handles));
742 EXPECT_EQ(static_cast<uint32_t>(kTestMessageHeader.size() +
743 kTestMessagePayloadSize),
744 payload_size);
745 EXPECT_EQ(0, memcmp(payload, kTestMessageHeader.data(),
746 kTestMessageHeader.size()));
747 EXPECT_EQ(0,
748 memcmp(static_cast<uint8_t*>(payload) + kTestMessageHeader.size(),
749 test_payload.data(), kTestMessagePayloadSize));
750
751 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[0]));
752 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[1]));
753 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
754 }
755 }
756
TEST_F(MessageTest,CorrectPayloadBufferBoundaries)757 TEST_F(MessageTest, CorrectPayloadBufferBoundaries) {
758 // Exercises writes to the full extent of a message's payload under various
759 // circumstances in an effort to catch any potential bugs in internal
760 // allocations or reported size from Mojo APIs.
761
762 MojoMessageHandle message;
763 void* buffer = nullptr;
764 uint32_t buffer_size = 0;
765 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
766 EXPECT_EQ(MOJO_RESULT_OK,
767 MojoAppendMessageData(message, 0, nullptr, 0, nullptr, &buffer,
768 &buffer_size));
769 // Fill the buffer end-to-end.
770 memset(buffer, 'x', buffer_size);
771
772 // Continuously grow and fill the message buffer several more times. Should
773 // not crash.
774 constexpr uint32_t kChunkSize = 4096;
775 constexpr size_t kNumIterations = 1000;
776 for (size_t i = 0; i < kNumIterations; ++i) {
777 EXPECT_EQ(MOJO_RESULT_OK,
778 MojoAppendMessageData(message, kChunkSize, nullptr, 0, nullptr,
779 &buffer, &buffer_size));
780 memset(buffer, 'x', buffer_size);
781 }
782
783 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
784 }
785
TEST_F(MessageTest,CommitInvalidMessageContents)786 TEST_F(MessageTest, CommitInvalidMessageContents) {
787 // Regression test for https://crbug.com/755127. Ensures that we don't crash
788 // if we attempt to commit the contents of an unserialized message.
789 MojoMessageHandle message;
790 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
791 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, nullptr, 0,
792 nullptr, nullptr, nullptr));
793 MojoHandle a, b;
794 CreateMessagePipe(&a, &b);
795 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, &a, 1, nullptr,
796 nullptr, nullptr));
797
798 UserMessageImpl::FailHandleSerializationForTesting(true);
799 MojoAppendMessageDataOptions options;
800 options.struct_size = sizeof(options);
801 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
802 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, nullptr, 0,
803 nullptr, nullptr, nullptr));
804 UserMessageImpl::FailHandleSerializationForTesting(false);
805 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
806 }
807
808 #if !defined(OS_IOS)
809
TEST_F(MessageTest,ExtendPayloadWithHandlesAttached)810 TEST_F(MessageTest, ExtendPayloadWithHandlesAttached) {
811 // Regression test for https://crbug.com/748996. Verifies that internal
812 // message objects do not retain invalid payload pointers across buffer
813 // relocations.
814
815 MojoHandle handles[5];
816 CreateMessagePipe(&handles[0], &handles[1]);
817 PlatformChannel channel;
818 handles[2] =
819 WrapPlatformHandle(channel.TakeLocalEndpoint().TakePlatformHandle())
820 .release()
821 .value();
822 handles[3] =
823 WrapPlatformHandle(channel.TakeRemoteEndpoint().TakePlatformHandle())
824 .release()
825 .value();
826 handles[4] = SharedBufferHandle::Create(64).release().value();
827
828 MojoMessageHandle message;
829 void* buffer = nullptr;
830 uint32_t buffer_size = 0;
831 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
832 EXPECT_EQ(MOJO_RESULT_OK,
833 MojoAppendMessageData(message, 0, handles, 5, nullptr, &buffer,
834 &buffer_size));
835
836 // Force buffer reallocation by extending the payload beyond the original
837 // buffer size. This should typically result in a relocation of the buffer as
838 // well -- at least often enough that breakage will be caught by automated
839 // tests.
840 MojoAppendMessageDataOptions options;
841 options.struct_size = sizeof(options);
842 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
843 uint32_t payload_size = buffer_size * 64;
844 EXPECT_EQ(MOJO_RESULT_OK,
845 MojoAppendMessageData(message, payload_size, nullptr, 0, &options,
846 &buffer, &buffer_size));
847 ASSERT_GE(buffer_size, payload_size);
848 memset(buffer, 'x', payload_size);
849
850 RunTestClient("ReadAndIgnoreMessage", [&](MojoHandle h) {
851 // Send the message out of process to exercise the regression path where
852 // internally cached, stale payload pointers may be dereferenced and written
853 // into.
854 EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, message, nullptr));
855 });
856 }
857
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndIgnoreMessage,MessageTest,h)858 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndIgnoreMessage, MessageTest, h) {
859 MojoTestBase::WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE);
860
861 MojoHandle handles[5];
862 MojoTestBase::ReadMessageWithHandles(h, handles, 5);
863 for (size_t i = 0; i < 5; ++i)
864 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[i]));
865 }
866
TEST_F(MessageTest,ExtendPayloadWithHandlesAttachedViaExtension)867 TEST_F(MessageTest, ExtendPayloadWithHandlesAttachedViaExtension) {
868 MojoHandle handles[5];
869 CreateMessagePipe(&handles[0], &handles[4]);
870 PlatformChannel channel;
871 handles[1] =
872 WrapPlatformHandle(channel.TakeLocalEndpoint().TakePlatformHandle())
873 .release()
874 .value();
875 handles[2] =
876 WrapPlatformHandle(channel.TakeRemoteEndpoint().TakePlatformHandle())
877 .release()
878 .value();
879 handles[3] = SharedBufferHandle::Create(64).release().value();
880
881 MojoMessageHandle message;
882 void* buffer = nullptr;
883 uint32_t buffer_size = 0;
884 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
885 EXPECT_EQ(MOJO_RESULT_OK,
886 MojoAppendMessageData(message, 0, handles, 1, nullptr, &buffer,
887 &buffer_size));
888 uint32_t payload_size = buffer_size * 64;
889 EXPECT_EQ(MOJO_RESULT_OK,
890 MojoAppendMessageData(message, payload_size, nullptr, 0, nullptr,
891 &buffer, nullptr));
892
893 // Add more handles.
894 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, handles + 1, 1,
895 nullptr, &buffer, nullptr));
896 MojoAppendMessageDataOptions options;
897 options.struct_size = sizeof(options);
898 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
899 EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, handles + 2, 3,
900 &options, &buffer, nullptr));
901 memset(buffer, 'x', payload_size);
902
903 RunTestClient("ReadMessageAndCheckPipe", [&](MojoHandle h) {
904 // Send the message out of process to exercise the regression path where
905 // internally cached, stale payload pointers may be dereferenced and written
906 // into.
907 EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, message, nullptr));
908 });
909 }
910
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadMessageAndCheckPipe,MessageTest,h)911 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadMessageAndCheckPipe, MessageTest, h) {
912 MojoTestBase::WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE);
913
914 const std::string kTestMessage("hey pipe");
915 MojoHandle handles[5];
916 MojoTestBase::ReadMessageWithHandles(h, handles, 5);
917 MojoTestBase::WriteMessage(handles[0], kTestMessage);
918 MojoTestBase::WaitForSignals(handles[4], MOJO_HANDLE_SIGNAL_READABLE);
919 EXPECT_EQ(kTestMessage, MojoTestBase::ReadMessage(handles[4]));
920 for (size_t i = 0; i < 5; ++i)
921 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[i]));
922 }
923
924 #endif // !defined(OS_IOS)
925
TEST_F(MessageTest,PartiallySerializedMessagesDontLeakHandles)926 TEST_F(MessageTest, PartiallySerializedMessagesDontLeakHandles) {
927 MojoMessageHandle message;
928 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
929
930 MojoHandle handles[2];
931 CreateMessagePipe(&handles[0], &handles[1]);
932
933 const std::string kTestMessagePart1("hello i am message.");
934 void* buffer;
935 uint32_t buffer_size;
936 EXPECT_EQ(MOJO_RESULT_OK,
937 MojoAppendMessageData(
938 message, static_cast<uint32_t>(kTestMessagePart1.size()),
939 nullptr, 0, nullptr, &buffer, &buffer_size));
940 ASSERT_GE(buffer_size, static_cast<uint32_t>(kTestMessagePart1.size()));
941 memcpy(buffer, kTestMessagePart1.data(), kTestMessagePart1.size());
942
943 EXPECT_EQ(MOJO_RESULT_OK,
944 MojoAppendMessageData(message, 0, handles, 1, nullptr, &buffer,
945 &buffer_size));
946
947 // This must close |handles[0]|, which we can detect by observing the
948 // signal state of |handles[1].
949 EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
950 EXPECT_EQ(MOJO_RESULT_OK,
951 WaitForSignals(handles[1], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
952 }
953
954 } // namespace
955 } // namespace core
956 } // namespace mojo
957