1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mach/notify_server.h"
16
17 #include <stddef.h>
18
19 #include "base/compiler_specific.h"
20 #include "base/mac/scoped_mach_port.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "test/mac/mach_errors.h"
24 #include "util/mach/mach_extensions.h"
25 #include "util/mach/mach_message.h"
26 #include "util/mach/mach_message_server.h"
27 #include "util/misc/implicit_cast.h"
28
29 namespace crashpad {
30 namespace test {
31 namespace {
32
33 using testing::AllOf;
34 using testing::DoAll;
35 using testing::Eq;
36 using testing::Invoke;
37 using testing::Pointee;
38 using testing::ResultOf;
39 using testing::Return;
40 using testing::SetArgPointee;
41 using testing::StrictMock;
42 using testing::WithArg;
43
44 //! \brief Adds a send right to an existing receive right.
45 //!
46 //! \param[in] receive_right The receive right to add a send right to.
47 //!
48 //! \return The send right, which will have the same name as the receive right.
49 //! On failure, `MACH_PORT_NULL` with a gtest failure added.
SendRightFromReceiveRight(mach_port_t receive_right)50 mach_port_t SendRightFromReceiveRight(mach_port_t receive_right) {
51 kern_return_t kr = mach_port_insert_right(
52 mach_task_self(), receive_right, receive_right, MACH_MSG_TYPE_MAKE_SEND);
53 if (kr != KERN_SUCCESS) {
54 EXPECT_EQ(kr, KERN_SUCCESS)
55 << MachErrorMessage(kr, "mach_port_insert_right");
56 return MACH_PORT_NULL;
57 }
58
59 return receive_right;
60 }
61
62 //! \brief Extracts a send-once right from a receive right.
63 //!
64 //! \param[in] receive_right The receive right to make a send-once right from.
65 //!
66 //! \return The send-once right. On failure, `MACH_PORT_NULL` with a gtest
67 //! failure added.
SendOnceRightFromReceiveRight(mach_port_t receive_right)68 mach_port_t SendOnceRightFromReceiveRight(mach_port_t receive_right) {
69 mach_port_t send_once_right;
70 mach_msg_type_name_t acquired_type;
71 kern_return_t kr = mach_port_extract_right(mach_task_self(),
72 receive_right,
73 MACH_MSG_TYPE_MAKE_SEND_ONCE,
74 &send_once_right,
75 &acquired_type);
76 if (kr != KERN_SUCCESS) {
77 EXPECT_EQ(kr, KERN_SUCCESS)
78 << MachErrorMessage(kr, "mach_port_extract_right");
79 return MACH_PORT_NULL;
80 }
81
82 EXPECT_EQ(acquired_type,
83 implicit_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND_ONCE));
84
85 return send_once_right;
86 }
87
88 //! \brief Deallocates a Mach port by calling `mach_port_deallocate()`.
89 //!
90 //! This function exists to adapt `mach_port_deallocate()` to a function that
91 //! accepts a single argument and has no return value. It can be used with the
92 //! testing::Invoke() gmock action.
93 //!
94 //! On failure, a gtest failure will be added.
MachPortDeallocate(mach_port_t port)95 void MachPortDeallocate(mach_port_t port) {
96 kern_return_t kr = mach_port_deallocate(mach_task_self(), port);
97 EXPECT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "mach_port_deallocate");
98 }
99
100 //! \brief Determines whether a specific right is held for a Mach port.
101 //!
102 //! \param[in] port The port to check for a right.
103 //! \param[in] right The right to check for.
104 //!
105 //! \return `true` if \a port has \a right, `false` otherwise. On faliure,
106 //! `false` with a gtest failure added.
IsRight(mach_port_t port,mach_port_type_t right)107 bool IsRight(mach_port_t port, mach_port_type_t right) {
108 mach_port_type_t type;
109 kern_return_t kr = mach_port_type(mach_task_self(), port, &type);
110 if (kr != KERN_SUCCESS) {
111 EXPECT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "mach_port_type");
112 return false;
113 }
114
115 return type & right;
116 }
117
118 //! \brief Determines whether a receive right is held for a Mach port.
119 //!
120 //! This is a special single-argument form of IsRight() for ease of use in a
121 //! gmock matcher.
122 //!
123 //! \param[in] port The port to check for a receive right.
124 //!
125 //! \return `true` if a receive right is held, `false` otherwise. On faliure,
126 //! `false` with a gtest failure added.
IsReceiveRight(mach_port_t port)127 bool IsReceiveRight(mach_port_t port) {
128 return IsRight(port, MACH_PORT_TYPE_RECEIVE);
129 }
130
131 //! \brief Returns the user reference count for port rights.
132 //!
133 //! \param[in] port The port whose user reference count should be returned.
134 //! \param[in] right The port right to return the user reference count for.
135 //!
136 //! \return The user reference count for the specified port and right. On
137 //! failure, `-1` with a gtest failure added.
RightRefCount(mach_port_t port,mach_port_right_t right)138 mach_port_urefs_t RightRefCount(mach_port_t port, mach_port_right_t right) {
139 mach_port_urefs_t refs;
140 kern_return_t kr = mach_port_get_refs(mach_task_self(), port, right, &refs);
141 if (kr != KERN_SUCCESS) {
142 EXPECT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "mach_port_get_refs");
143 return -1;
144 }
145
146 return refs;
147 }
148
149 //! \brief Returns the user reference count for a port’s dead-name rights.
150 //!
151 //! This is a special single-argument form of RightRefCount() for ease of use in
152 //! a gmock matcher.
153 //!
154 //! \param[in] port The port whose dead-name user reference count should be
155 //! returned.
156 //!
157 //! \return The user reference count for the port’s dead-name rights. On
158 //! failure, `-1` with a gtest failure added.
DeadNameRightRefCount(mach_port_t port)159 mach_port_urefs_t DeadNameRightRefCount(mach_port_t port) {
160 return RightRefCount(port, MACH_PORT_RIGHT_DEAD_NAME);
161 }
162
163 class NotifyServerTestBase : public testing::Test,
164 public NotifyServer::Interface {
165 public:
166 // NotifyServer::Interface:
167
168 MOCK_METHOD3(DoMachNotifyPortDeleted,
169 kern_return_t(notify_port_t notify,
170 mach_port_name_t name,
171 const mach_msg_trailer_t* trailer));
172
173 MOCK_METHOD4(DoMachNotifyPortDestroyed,
174 kern_return_t(notify_port_t notify,
175 mach_port_t rights,
176 const mach_msg_trailer_t* trailer,
177 bool* destroy_request));
178
179 MOCK_METHOD3(DoMachNotifyNoSenders,
180 kern_return_t(notify_port_t notify,
181 mach_port_mscount_t mscount,
182 const mach_msg_trailer_t* trailer));
183
184 MOCK_METHOD2(DoMachNotifySendOnce,
185 kern_return_t(notify_port_t notify,
186 const mach_msg_trailer_t* trailer));
187
188 MOCK_METHOD3(DoMachNotifyDeadName,
189 kern_return_t(notify_port_t notify,
190 mach_port_name_t name,
191 const mach_msg_trailer_t* trailer));
192
193 protected:
NotifyServerTestBase()194 NotifyServerTestBase() : testing::Test(), NotifyServer::Interface() {}
195
~NotifyServerTestBase()196 ~NotifyServerTestBase() override {}
197
198 //! \brief Requests a Mach port notification.
199 //!
200 //! \a name, \a variant, and \a sync are passed as-is to
201 //! `mach_port_request_notification()`. The notification will be sent to a
202 //! send-once right made from ServerPort(). Any previous send right for the
203 //! notification will be deallocated.
204 //!
205 //! \return `true` on success, `false` on failure with a gtest failure added.
RequestMachPortNotification(mach_port_t name,mach_msg_id_t variant,mach_port_mscount_t sync)206 bool RequestMachPortNotification(mach_port_t name,
207 mach_msg_id_t variant,
208 mach_port_mscount_t sync) {
209 mach_port_t previous;
210 kern_return_t kr =
211 mach_port_request_notification(mach_task_self(),
212 name,
213 variant,
214 sync,
215 ServerPort(),
216 MACH_MSG_TYPE_MAKE_SEND_ONCE,
217 &previous);
218 if (kr != KERN_SUCCESS) {
219 EXPECT_EQ(kr, KERN_SUCCESS)
220 << MachErrorMessage(kr, "mach_port_request_notification");
221 return false;
222 }
223
224 base::mac::ScopedMachSendRight previous_owner(previous);
225 EXPECT_EQ(previous, kMachPortNull);
226
227 return true;
228 }
229
230 //! \brief Runs a NotifyServer Mach message server.
231 //!
232 //! The server will listen on ServerPort() in persistent nonblocking mode, and
233 //! dispatch received messages to the appropriate NotifyServer::Interface
234 //! method. gmock expectations check that the proper method, if any, is called
235 //! exactly once, and that no undesired methods are called.
236 //!
237 //! MachMessageServer::Run() is expected to return `MACH_RCV_TIMED_OUT`,
238 //! because it runs in persistent nonblocking mode. If it returns anything
239 //! else, a gtest assertion is added.
RunServer()240 void RunServer() {
241 NotifyServer notify_server(this);
242 mach_msg_return_t mr =
243 MachMessageServer::Run(¬ify_server,
244 ServerPort(),
245 kMachMessageReceiveAuditTrailer,
246 MachMessageServer::kPersistent,
247 MachMessageServer::kReceiveLargeError,
248 kMachMessageTimeoutNonblocking);
249 ASSERT_EQ(mr, MACH_RCV_TIMED_OUT)
250 << MachErrorMessage(mr, "MachMessageServer::Run");
251 }
252
253 //! \brief Returns the receive right to be used for the server.
254 //!
255 //! This receive right is created lazily on a per-test basis. It is destroyed
256 //! by TearDown() at the conclusion of each test.
257 //!
258 //! \return The server port receive right, creating it if one has not yet been
259 //! established for the current test. On failure, returns `MACH_PORT_NULL`
260 //! with a gtest failure added.
ServerPort()261 mach_port_t ServerPort() {
262 if (!server_port_.is_valid()) {
263 server_port_.reset(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
264 EXPECT_TRUE(server_port_.is_valid());
265 }
266
267 return server_port_.get();
268 }
269
270 // testing::Test:
TearDown()271 void TearDown() override {
272 server_port_.reset();
273 }
274
275 private:
276 base::mac::ScopedMachReceiveRight server_port_;
277
278 DISALLOW_COPY_AND_ASSIGN(NotifyServerTestBase);
279 };
280
281 using NotifyServerTest = StrictMock<NotifyServerTestBase>;
282
TEST_F(NotifyServerTest,Basic)283 TEST_F(NotifyServerTest, Basic) {
284 NotifyServer server(this);
285
286 std::set<mach_msg_id_t> expect_request_ids;
287 expect_request_ids.insert(MACH_NOTIFY_PORT_DELETED);
288 expect_request_ids.insert(MACH_NOTIFY_PORT_DESTROYED);
289 expect_request_ids.insert(MACH_NOTIFY_NO_SENDERS);
290 expect_request_ids.insert(MACH_NOTIFY_SEND_ONCE);
291 expect_request_ids.insert(MACH_NOTIFY_DEAD_NAME);
292 EXPECT_EQ(server.MachMessageServerRequestIDs(), expect_request_ids);
293
294 // The port-destroyed notification is the largest request message in the
295 // subsystem. <mach/notify.h> defines the same structure, but with a basic
296 // trailer, so use offsetof to get the size of the basic structure without any
297 // trailer.
298 EXPECT_EQ(server.MachMessageServerRequestSize(),
299 offsetof(mach_port_destroyed_notification_t, trailer));
300
301 mig_reply_error_t reply;
302 EXPECT_EQ(server.MachMessageServerReplySize(), sizeof(reply));
303 }
304
305 // When no notifications are requested, nothing should happen.
TEST_F(NotifyServerTest,NoNotification)306 TEST_F(NotifyServerTest, NoNotification) {
307 RunServer();
308 }
309
310 // When a send-once right with a dead-name notification request is deallocated,
311 // a port-deleted notification should be generated.
TEST_F(NotifyServerTest,MachNotifyPortDeleted)312 TEST_F(NotifyServerTest, MachNotifyPortDeleted) {
313 base::mac::ScopedMachReceiveRight receive_right(
314 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
315 ASSERT_TRUE(receive_right.is_valid());
316
317 base::mac::ScopedMachSendRight send_once_right(
318 SendOnceRightFromReceiveRight(receive_right.get()));
319 ASSERT_TRUE(send_once_right.is_valid());
320
321 ASSERT_TRUE(RequestMachPortNotification(
322 send_once_right.get(), MACH_NOTIFY_DEAD_NAME, 0));
323
324 EXPECT_CALL(
325 *this,
326 DoMachNotifyPortDeleted(ServerPort(),
327 send_once_right.get(),
328 ResultOf(AuditPIDFromMachMessageTrailer, 0)))
329 .WillOnce(Return(MIG_NO_REPLY))
330 .RetiresOnSaturation();
331
332 send_once_right.reset();
333
334 RunServer();
335 }
336
337 // When a receive right with a port-destroyed notification request is destroyed,
338 // a port-destroyed notification should be generated.
TEST_F(NotifyServerTest,MachNotifyPortDestroyed)339 TEST_F(NotifyServerTest, MachNotifyPortDestroyed) {
340 base::mac::ScopedMachReceiveRight receive_right(
341 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
342 ASSERT_TRUE(receive_right.is_valid());
343
344 ASSERT_TRUE(RequestMachPortNotification(
345 receive_right.get(), MACH_NOTIFY_PORT_DESTROYED, 0));
346
347 EXPECT_CALL(
348 *this,
349 DoMachNotifyPortDestroyed(ServerPort(),
350 ResultOf(IsReceiveRight, true),
351 ResultOf(AuditPIDFromMachMessageTrailer, 0),
352 Pointee(Eq(false))))
353 .WillOnce(DoAll(SetArgPointee<3>(true), Return(MIG_NO_REPLY)))
354 .RetiresOnSaturation();
355
356 receive_right.reset();
357
358 RunServer();
359 }
360
361 // When a receive right with a port-destroyed notification request is not
362 // destroyed, no port-destroyed notification should be generated.
TEST_F(NotifyServerTest,MachNotifyPortDestroyed_NoNotification)363 TEST_F(NotifyServerTest, MachNotifyPortDestroyed_NoNotification) {
364 base::mac::ScopedMachReceiveRight receive_right(
365 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
366 ASSERT_TRUE(receive_right.is_valid());
367
368 ASSERT_TRUE(RequestMachPortNotification(
369 receive_right.get(), MACH_NOTIFY_PORT_DESTROYED, 0));
370
371 RunServer();
372 }
373
374 // When a no-senders notification request is registered for a receive right with
375 // no senders, a no-senders notification should be generated.
TEST_F(NotifyServerTest,MachNotifyNoSenders_NoSendRight)376 TEST_F(NotifyServerTest, MachNotifyNoSenders_NoSendRight) {
377 base::mac::ScopedMachReceiveRight receive_right(
378 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
379 ASSERT_TRUE(receive_right.is_valid());
380
381 ASSERT_TRUE(RequestMachPortNotification(
382 receive_right.get(), MACH_NOTIFY_NO_SENDERS, 0));
383
384 EXPECT_CALL(*this,
385 DoMachNotifyNoSenders(
386 ServerPort(), 0, ResultOf(AuditPIDFromMachMessageTrailer, 0)))
387 .WillOnce(Return(MIG_NO_REPLY))
388 .RetiresOnSaturation();
389
390 RunServer();
391 }
392
393 // When the last send right corresponding to a receive right with a no-senders
394 // notification request is deallocated, a no-senders notification should be
395 // generated.
TEST_F(NotifyServerTest,MachNotifyNoSenders_SendRightDeallocated)396 TEST_F(NotifyServerTest, MachNotifyNoSenders_SendRightDeallocated) {
397 base::mac::ScopedMachReceiveRight receive_right(
398 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
399 ASSERT_TRUE(receive_right.is_valid());
400
401 base::mac::ScopedMachSendRight send_right(
402 SendRightFromReceiveRight(receive_right.get()));
403 ASSERT_TRUE(send_right.is_valid());
404
405 ASSERT_TRUE(RequestMachPortNotification(
406 receive_right.get(), MACH_NOTIFY_NO_SENDERS, 1));
407
408 EXPECT_CALL(*this,
409 DoMachNotifyNoSenders(
410 ServerPort(), 1, ResultOf(AuditPIDFromMachMessageTrailer, 0)))
411 .WillOnce(Return(MIG_NO_REPLY))
412 .RetiresOnSaturation();
413
414 send_right.reset();
415
416 RunServer();
417 }
418
419 // When the a receive right with a no-senders notification request never loses
420 // all senders, no no-senders notification should be generated.
TEST_F(NotifyServerTest,MachNotifyNoSenders_NoNotification)421 TEST_F(NotifyServerTest, MachNotifyNoSenders_NoNotification) {
422 base::mac::ScopedMachReceiveRight receive_right(
423 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
424 ASSERT_TRUE(receive_right.is_valid());
425
426 base::mac::ScopedMachSendRight send_right_0(
427 SendRightFromReceiveRight(receive_right.get()));
428 ASSERT_TRUE(send_right_0.is_valid());
429
430 base::mac::ScopedMachSendRight send_right_1(
431 SendRightFromReceiveRight(receive_right.get()));
432 ASSERT_TRUE(send_right_1.is_valid());
433
434 ASSERT_TRUE(RequestMachPortNotification(
435 receive_right.get(), MACH_NOTIFY_NO_SENDERS, 1));
436
437 send_right_1.reset();
438
439 RunServer();
440
441 EXPECT_EQ(RightRefCount(receive_right.get(), MACH_PORT_RIGHT_RECEIVE), 1u);
442 EXPECT_EQ(RightRefCount(receive_right.get(), MACH_PORT_RIGHT_SEND), 1u);
443 }
444
445 // When a send-once right is deallocated without being used, a send-once
446 // notification notification should be sent via the send-once right.
TEST_F(NotifyServerTest,MachNotifySendOnce_ExplicitDeallocation)447 TEST_F(NotifyServerTest, MachNotifySendOnce_ExplicitDeallocation) {
448 base::mac::ScopedMachSendRight send_once_right(
449 SendOnceRightFromReceiveRight(ServerPort()));
450 ASSERT_TRUE(send_once_right.is_valid());
451
452 EXPECT_CALL(*this,
453 DoMachNotifySendOnce(ServerPort(),
454 ResultOf(AuditPIDFromMachMessageTrailer, 0)))
455 .WillOnce(Return(MIG_NO_REPLY))
456 .RetiresOnSaturation();
457
458 send_once_right.reset();
459
460 RunServer();
461 }
462
463 // When a send-once right is sent to a receiver that never dequeues the message,
464 // the send-once right is destroyed, and a send-once notification should appear
465 // on the reply port.
TEST_F(NotifyServerTest,MachNotifySendOnce_ImplicitDeallocation)466 TEST_F(NotifyServerTest, MachNotifySendOnce_ImplicitDeallocation) {
467 base::mac::ScopedMachReceiveRight receive_right(
468 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
469 ASSERT_TRUE(receive_right.is_valid());
470
471 mach_msg_empty_send_t message = {};
472 message.header.msgh_bits =
473 MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
474 message.header.msgh_size = sizeof(message);
475 message.header.msgh_remote_port = receive_right.get();
476 message.header.msgh_local_port = ServerPort();
477 mach_msg_return_t mr = mach_msg(&message.header,
478 MACH_SEND_MSG | MACH_SEND_TIMEOUT,
479 message.header.msgh_size,
480 0,
481 MACH_PORT_NULL,
482 0,
483 MACH_PORT_NULL);
484 ASSERT_EQ(mr, MACH_MSG_SUCCESS) << MachErrorMessage(mr, "mach_msg");
485
486 EXPECT_CALL(*this,
487 DoMachNotifySendOnce(ServerPort(),
488 ResultOf(AuditPIDFromMachMessageTrailer, 0)))
489 .WillOnce(Return(MIG_NO_REPLY))
490 .RetiresOnSaturation();
491
492 receive_right.reset();
493
494 RunServer();
495 }
496
497 // When the receive right corresponding to a send-once right with a dead-name
498 // notification request is destroyed, a dead-name notification should be
499 // generated.
TEST_F(NotifyServerTest,MachNotifyDeadName)500 TEST_F(NotifyServerTest, MachNotifyDeadName) {
501 base::mac::ScopedMachReceiveRight receive_right(
502 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
503 ASSERT_TRUE(receive_right.is_valid());
504
505 base::mac::ScopedMachSendRight send_once_right(
506 SendOnceRightFromReceiveRight(receive_right.get()));
507 ASSERT_TRUE(send_once_right.is_valid());
508
509 ASSERT_TRUE(RequestMachPortNotification(
510 send_once_right.get(), MACH_NOTIFY_DEAD_NAME, 0));
511
512 // send_once_right becomes a dead name with the send-once right’s original
513 // user reference count of 1, but the dead-name notification increments the
514 // dead-name reference count, so it becomes 2. Take care to deallocate that
515 // reference. The original reference is managed by send_once_right_owner.
516 EXPECT_CALL(*this,
517 DoMachNotifyDeadName(ServerPort(),
518 AllOf(send_once_right.get(),
519 ResultOf(DeadNameRightRefCount, 2)),
520 ResultOf(AuditPIDFromMachMessageTrailer, 0)))
521 .WillOnce(
522 DoAll(WithArg<1>(Invoke(MachPortDeallocate)), Return(MIG_NO_REPLY)))
523 .RetiresOnSaturation();
524
525 receive_right.reset();
526
527 RunServer();
528
529 EXPECT_TRUE(IsRight(send_once_right.get(), MACH_PORT_TYPE_DEAD_NAME));
530
531 EXPECT_EQ(RightRefCount(send_once_right.get(), MACH_PORT_RIGHT_SEND_ONCE),
532 0u);
533 EXPECT_EQ(DeadNameRightRefCount(send_once_right.get()), 1u);
534 }
535
536 // When the receive right corresponding to a send-once right with a dead-name
537 // notification request is not destroyed, no dead-name notification should be
538 // generated.
TEST_F(NotifyServerTest,MachNotifyDeadName_NoNotification)539 TEST_F(NotifyServerTest, MachNotifyDeadName_NoNotification) {
540 base::mac::ScopedMachReceiveRight receive_right(
541 NewMachPort(MACH_PORT_RIGHT_RECEIVE));
542 ASSERT_TRUE(receive_right.is_valid());
543
544 base::mac::ScopedMachSendRight send_once_right(
545 SendOnceRightFromReceiveRight(receive_right.get()));
546 ASSERT_TRUE(send_once_right.is_valid());
547
548 ASSERT_TRUE(RequestMachPortNotification(
549 send_once_right.get(), MACH_NOTIFY_DEAD_NAME, 0));
550
551 RunServer();
552
553 EXPECT_FALSE(IsRight(send_once_right.get(), MACH_PORT_TYPE_DEAD_NAME));
554
555 EXPECT_EQ(RightRefCount(send_once_right.get(), MACH_PORT_RIGHT_SEND_ONCE),
556 1u);
557 EXPECT_EQ(DeadNameRightRefCount(send_once_right.get()), 0u);
558 }
559
560 } // namespace
561 } // namespace test
562 } // namespace crashpad
563