Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: util/mach/exception_ports_test.cc

Issue 549023005: Add ExceptionPorts and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Rebase Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/exception_ports.h"
16
17 #include <dispatch/dispatch.h>
18 #include <mach/mach.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <unistd.h>
22
23 #include "base/basictypes.h"
24 #include "base/logging.h"
25 #include "base/mac/mach_logging.h"
26 #include "base/mac/scoped_mach_port.h"
27 #include "base/strings/stringprintf.h"
28 #include "gtest/gtest.h"
29 #include "util/file/fd_io.h"
30 #include "util/mach/exc_server_variants.h"
31 #include "util/mach/mach_extensions.h"
32 #include "util/misc/scoped_forbid_return.h"
33 #include "util/test/errors.h"
34 #include "util/test/mac/mach_errors.h"
35 #include "util/test/mac/mach_multiprocess.h"
36
37 namespace {
38
39 using namespace crashpad;
40 using namespace crashpad::test;
41
42 // Calls GetExceptionPorts() on its |exception_ports| argument to look up the
43 // EXC_MASK_CRASH handler. If |expect_port| is not MACH_PORT_NULL, it expects to
44 // find a handler for this mask whose port matches |expect_port| and whose
45 // behavior matches |expect_behavior| exactly. In this case, if
46 // |expect_behavior| is a state-carrying behavior, the looked-up thread state
47 // flavor is expected to be MACHINE_THREAD_STATE, otherwise, it is expected to
48 // be THREAD_STATE_NONE. If |expect_port| is MACH_PORT_NULL, no handler for
49 // EXC_MASK_CRASH is expected to be found.
50 //
51 // A second GetExceptionPorts() lookup is also performed on a wider exception
52 // mask, EXC_MASK_ALL | EXC_MASK_CRASH. The EXC_MASK_CRASH handler’s existence
53 // and properties from this second lookup are validated in the same way.
54 //
55 // This function uses gtest EXPECT_* and ASSERT_* macros to perform its
56 // validation.
57 void TestGetExceptionPorts(const ExceptionPorts& exception_ports,
58 mach_port_t expect_port,
59 exception_behavior_t expect_behavior) {
60 const exception_mask_t kExceptionMask = EXC_MASK_CRASH;
61
62 thread_state_flavor_t expect_flavor = (expect_behavior == EXCEPTION_DEFAULT)
63 ? THREAD_STATE_NONE
64 : MACHINE_THREAD_STATE;
65
66 std::vector<ExceptionPorts::ExceptionHandler> crash_handler;
67 kern_return_t kr =
68 exception_ports.GetExceptionPorts(kExceptionMask, &crash_handler);
69 ASSERT_EQ(KERN_SUCCESS, kr)
70 << MachErrorMessage(kr,
71 base::StringPrintf("%s_get_exception_ports",
72 exception_ports.TargetTypeName()));
73
74 if (expect_port != MACH_PORT_NULL) {
75 ASSERT_EQ(1u, crash_handler.size());
76 base::mac::ScopedMachSendRight port_owner(crash_handler[0].port);
77
78 EXPECT_EQ(kExceptionMask, crash_handler[0].mask);
79 EXPECT_EQ(expect_port, crash_handler[0].port);
80 EXPECT_EQ(expect_behavior, crash_handler[0].behavior);
81 EXPECT_EQ(expect_flavor, crash_handler[0].flavor);
82 } else {
83 EXPECT_TRUE(crash_handler.empty());
84 }
85
86 std::vector<ExceptionPorts::ExceptionHandler> handlers;
87 kr = exception_ports.GetExceptionPorts(ExcMaskAll() | EXC_MASK_CRASH,
88 &handlers);
89 ASSERT_EQ(KERN_SUCCESS, kr)
90 << MachErrorMessage(kr,
91 base::StringPrintf("%s_get_exception_ports",
92 exception_ports.TargetTypeName()));
93
94 EXPECT_GE(handlers.size(), crash_handler.size());
95 bool found = false;
96 for (const ExceptionPorts::ExceptionHandler& handler : handlers) {
97 if ((handler.mask & kExceptionMask) != 0) {
98 base::mac::ScopedMachSendRight port_owner(handler.port);
99
100 EXPECT_FALSE(found);
101 found = true;
102 EXPECT_EQ(expect_port, handler.port);
103 EXPECT_EQ(expect_behavior, handler.behavior);
104 EXPECT_EQ(expect_flavor, handler.flavor);
105 }
106 }
107
108 if (expect_port != MACH_PORT_NULL) {
109 EXPECT_TRUE(found);
110 } else {
111 EXPECT_FALSE(found);
112 }
113 }
114
115 class TestExceptionPorts : public UniversalMachExcServer,
116 public MachMultiprocess {
117 public:
118 // Where to call ExceptionPorts::SetExceptionPort() from.
119 enum SetType {
120 // Call it from the child process on itself.
121 kSetInProcess = 0,
122
123 // Call it from the parent process on the child.
124 kSetOutOfProcess,
125 };
126
127 // Which entities to set exception ports for.
128 enum SetOn {
129 kSetOnTaskOnly = 0,
130 kSetOnTaskAndThreads,
131 };
132
133 // Which thread in the child process is expected to crash.
134 enum WhoCrashes {
135 kNobodyCrashes = 0,
136 kMainThreadCrashes,
137 kOtherThreadCrashes,
138 };
139
140 TestExceptionPorts(SetType set_type, SetOn set_on, WhoCrashes who_crashes)
141 : UniversalMachExcServer(),
142 MachMultiprocess(),
143 set_type_(set_type),
144 set_on_(set_on),
145 who_crashes_(who_crashes),
146 handled_(false) {}
147
148 SetType set_type() const { return set_type_; }
149 SetOn set_on() const { return set_on_; }
150 WhoCrashes who_crashes() const { return who_crashes_; }
151
152 // UniversalMachExcServer:
153
154 virtual kern_return_t CatchMachException(
155 exception_behavior_t behavior,
156 exception_handler_t exception_port,
157 thread_t thread,
158 task_t task,
159 exception_type_t exception,
160 const mach_exception_data_type_t* code,
161 mach_msg_type_number_t code_count,
162 thread_state_flavor_t* flavor,
163 const natural_t* old_state,
164 mach_msg_type_number_t old_state_count,
165 thread_state_t new_state,
166 mach_msg_type_number_t* new_state_count,
167 bool* destroy_complex_request) override {
168 *destroy_complex_request = true;
169
170 EXPECT_FALSE(handled_);
171 handled_ = true;
172
173 // To be able to distinguish between which handler was actually triggered,
174 // the different handlers are registered with different behavior values.
175 exception_behavior_t expect_behavior;
176 if (set_on_ == kSetOnTaskOnly) {
177 expect_behavior = EXCEPTION_DEFAULT;
178 } else if (who_crashes_ == kMainThreadCrashes) {
179 expect_behavior = EXCEPTION_STATE;
180 } else if (who_crashes_ == kOtherThreadCrashes) {
181 expect_behavior = EXCEPTION_STATE_IDENTITY;
182 } else {
183 NOTREACHED();
184 expect_behavior = 0;
185 }
186
187 EXPECT_EQ(expect_behavior, behavior);
188
189 EXPECT_EQ(LocalPort(), exception_port);
190
191 EXPECT_EQ(EXC_CRASH, exception);
192 EXPECT_EQ(2u, code_count);
193
194 if (code_count > 1) {
195 // The signal that terminated the process is stored in code[0] along with
196 // some other data. See 10.9.4 xnu-2422.110.17/bsd/kern/kern_exit.c
197 // proc_prepareexit().
198 int sig = (code[0] >> 24) & 0xff;
199
200 // The child crashed with a division by zero, which shows up as SIGFPE.
201 // This was chosen because it’s unlikely to be generated by testing or
202 // assertion failures.
203 EXPECT_EQ(SIGFPE, sig);
204
205 SetExpectedChildTermination(kTerminationSignal, sig);
206 }
207
208 // Even for an EXC_CRASH handler, returning KERN_SUCCESS with a
209 // state-carrying reply will cause the kernel to try to set a new thread
210 // state, leading to a perceptible waste of time. Returning
211 // MACH_RCV_PORT_DIED is the only way to suppress this behavior while also
212 // preventing the kernel from looking for another (host-level) EXC_CRASH
213 // handler. See 10.9.4 xnu-2422.110.17/osfmk/kern/exception.c
214 // exception_triage().
215 exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES;
216 bool has_state = basic_behavior == EXCEPTION_STATE ||
217 basic_behavior == EXCEPTION_STATE_IDENTITY;
218 return has_state ? MACH_RCV_PORT_DIED : KERN_SUCCESS;
219 }
220
221 private:
222 class Child {
223 public:
224 explicit Child(TestExceptionPorts* test_exception_ports)
225 : test_exception_ports_(test_exception_ports),
226 thread_(),
227 init_semaphore_(dispatch_semaphore_create(0)),
228 crash_semaphore_(dispatch_semaphore_create(0)) {}
229
230 ~Child() {
231 dispatch_release(crash_semaphore_);
232 dispatch_release(init_semaphore_);
233 }
234
235 void Run() {
236 ExceptionPorts self_task_ports(ExceptionPorts::kTargetTypeTask,
237 MACH_PORT_NULL);
238 ExceptionPorts self_thread_ports(ExceptionPorts::kTargetTypeThread,
239 MACH_PORT_NULL);
240
241 mach_port_t remote_port = test_exception_ports_->RemotePort();
242
243 // Set the task’s and this thread’s exception ports, if appropriate.
244 if (test_exception_ports_->set_type() == kSetInProcess) {
245 kern_return_t kr = self_task_ports.SetExceptionPort(
246 EXC_MASK_CRASH, remote_port, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
247 ASSERT_EQ(KERN_SUCCESS, kr)
248 << MachErrorMessage(kr, "task_set_exception_ports");
249
250 if (test_exception_ports_->set_on() == kSetOnTaskAndThreads) {
251 kern_return_t kr =
252 self_thread_ports.SetExceptionPort(EXC_MASK_CRASH,
253 remote_port,
254 EXCEPTION_STATE,
255 MACHINE_THREAD_STATE);
256 ASSERT_EQ(KERN_SUCCESS, kr)
257 << MachErrorMessage(kr, "thread_set_exception_ports");
258 }
259 }
260
261 int rv_int = pthread_create(&thread_, NULL, ThreadMainThunk, this);
262 ASSERT_EQ(0, rv_int);
263
264 // Wait for the new thread to be ready.
265 long rv_long =
266 dispatch_semaphore_wait(init_semaphore_, DISPATCH_TIME_FOREVER);
267 ASSERT_EQ(0, rv_long);
268
269 // Tell the parent process that everything is set up.
270 char c = '\0';
271 ssize_t rv_ssize = WriteFD(test_exception_ports_->WritePipeFD(), &c, 1);
272 ASSERT_EQ(1, rv_ssize) << ErrnoMessage("write");
273
274 // Wait for the parent process to say that its end is set up.
275 rv_ssize = ReadFD(test_exception_ports_->ReadPipeFD(), &c, 1);
276 ASSERT_EQ(1, rv_ssize) << ErrnoMessage("read");
277 EXPECT_EQ('\0', c);
278
279 // Regardless of where ExceptionPorts::SetExceptionPort() ran,
280 // ExceptionPorts::GetExceptionPorts() can always be tested in-process.
281 {
282 SCOPED_TRACE("task");
283 TestGetExceptionPorts(self_task_ports, remote_port, EXCEPTION_DEFAULT);
284 }
285
286 {
287 SCOPED_TRACE("main_thread");
288 mach_port_t thread_handler =
289 (test_exception_ports_->set_on() == kSetOnTaskAndThreads)
290 ? remote_port
291 : MACH_PORT_NULL;
292 TestGetExceptionPorts(
293 self_thread_ports, thread_handler, EXCEPTION_STATE);
294 }
295
296 // Let the other thread know it’s safe to proceed.
297 dispatch_semaphore_signal(crash_semaphore_);
298
299 // If this thread is the one that crashes, do it.
300 if (test_exception_ports_->who_crashes() == kMainThreadCrashes) {
301 Crash();
302 }
303
304 // Reap the other thread.
305 rv_int = pthread_join(thread_, NULL);
306 ASSERT_EQ(0, rv_int);
307 }
308
309 private:
310 // Calls ThreadMain().
311 static void* ThreadMainThunk(void* argument) {
312 Child* self = reinterpret_cast<Child*>(argument);
313 return self->ThreadMain();
314 }
315
316 // Runs the “other” thread.
317 void* ThreadMain() {
318 ExceptionPorts self_thread_ports(ExceptionPorts::kTargetTypeThread,
319 MACH_PORT_NULL);
320 mach_port_t remote_port = test_exception_ports_->RemotePort();
321
322 // Set this thread’s exception handler, if appropriate.
323 if (test_exception_ports_->set_type() == kSetInProcess &&
324 test_exception_ports_->set_on() == kSetOnTaskAndThreads) {
325 kern_return_t kr =
326 self_thread_ports.SetExceptionPort(EXC_MASK_CRASH,
327 remote_port,
328 EXCEPTION_STATE_IDENTITY,
329 MACHINE_THREAD_STATE);
330 MACH_CHECK(kr == KERN_SUCCESS, kr) << "thread_set_exception_ports";
331 }
332
333 // Let the main thread know that this thread is ready.
334 dispatch_semaphore_signal(init_semaphore_);
335
336 // Wait for the main thread to signal that it’s safe to proceed.
337 long rv =
338 dispatch_semaphore_wait(crash_semaphore_, DISPATCH_TIME_FOREVER);
339 CHECK_EQ(0, rv) << "dispatch_semaphore_wait";
340
341 // Regardless of where ExceptionPorts::SetExceptionPort() ran,
342 // ExceptionPorts::GetExceptionPorts() can always be tested in-process.
343 {
344 SCOPED_TRACE("other_thread");
345 mach_port_t thread_handler =
346 (test_exception_ports_->set_on() == kSetOnTaskAndThreads)
347 ? remote_port
348 : MACH_PORT_NULL;
349 TestGetExceptionPorts(
350 self_thread_ports, thread_handler, EXCEPTION_STATE_IDENTITY);
351 }
352
353 // If this thread is the one that crashes, do it.
354 if (test_exception_ports_->who_crashes() == kOtherThreadCrashes) {
355 Crash();
356 }
357
358 return NULL;
359 }
360
361 // Crashes by performing a division by zero. The assignment is present to
362 // avoid optimizing zero_ out entirely by making it appear that its value
363 // might change.
364 static void Crash() { zero_ = 1 / zero_; }
365
366 // The parent object.
367 TestExceptionPorts* test_exception_ports_; // weak
368
369 // The “other” thread.
370 pthread_t thread_;
371
372 // The main thread waits on this for the other thread to start up and
373 // perform its own initialization.
374 dispatch_semaphore_t init_semaphore_;
375
376 // The child thread waits on this for the parent thread to indicate that the
377 // child can test its exception ports and possibly crash, as appropriate.
378 dispatch_semaphore_t crash_semaphore_;
379
380 // Always zero. Crash() divides by this in order to trigger a crash. This is
381 // structured as a static volatile int to ward off aggressive compiler
382 // optimizations.
383 static volatile int zero_;
384
385 DISALLOW_COPY_AND_ASSIGN(Child);
386 };
387
388 // MachMultiprocess:
389
390 virtual void MachMultiprocessParent() override {
391 // Wait for the child process to be ready. It needs to have all of its
392 // threads set up before proceeding if in kSetOutOfProcess mode.
393 char c;
394 ssize_t rv = ReadFD(ReadPipeFD(), &c, 1);
395 ASSERT_EQ(1, rv) << ErrnoMessage("read");
396 EXPECT_EQ('\0', c);
397
398 mach_port_t local_port = LocalPort();
399
400 // Get an ExceptionPorts object for the task and each of its threads.
401 ExceptionPorts task_ports(ExceptionPorts::kTargetTypeTask, ChildTask());
402 EXPECT_EQ("task", task_ports.TargetTypeName());
403
404 // Hopefully the threads returned by task_threads() are in order, with the
405 // main thread first and the other thread second. This is currently always
406 // the case, although nothing guarantees that it will remain so.
407 thread_act_array_t threads;
408 mach_msg_type_number_t thread_count = 0;
409 kern_return_t kr = task_threads(ChildTask(), &threads, &thread_count);
410 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "task_threads");
411
412 ScopedForbidReturn threads_need_owners;
413 ASSERT_EQ(2u, thread_count);
414 base::mac::ScopedMachSendRight main_thread(threads[0]);
415 base::mac::ScopedMachSendRight other_thread(threads[1]);
416 threads_need_owners.Disarm();
417
418 ExceptionPorts main_thread_ports(ExceptionPorts::kTargetTypeThread,
419 main_thread);
420 ExceptionPorts other_thread_ports(ExceptionPorts::kTargetTypeThread,
421 other_thread);
422 EXPECT_EQ("thread", main_thread_ports.TargetTypeName());
423 EXPECT_EQ("thread", other_thread_ports.TargetTypeName());
424
425 if (set_type_ == kSetOutOfProcess) {
426 // Test ExceptionPorts::SetExceptionPorts() being called from
427 // out-of-process.
428 //
429 // local_port is only a receive right, but a send right is needed for
430 // ExceptionPorts::SetExceptionPort(). Make a send right, which can be
431 // deallocated once the calls to ExceptionPorts::SetExceptionPort() are
432 // done.
433 kr = mach_port_insert_right(
434 mach_task_self(), local_port, local_port, MACH_MSG_TYPE_MAKE_SEND);
435 ASSERT_EQ(KERN_SUCCESS, kr)
436 << MachErrorMessage(kr, "mach_port_insert_right");
437 base::mac::ScopedMachSendRight send_owner(local_port);
438
439 kr = task_ports.SetExceptionPort(
440 EXC_MASK_CRASH, local_port, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
441 ASSERT_EQ(KERN_SUCCESS, kr)
442 << MachErrorMessage(kr, "task_set_exception_ports");
443
444 if (set_on_ == kSetOnTaskAndThreads) {
445 kr = main_thread_ports.SetExceptionPort(
446 EXC_MASK_CRASH, local_port, EXCEPTION_STATE, MACHINE_THREAD_STATE);
447 ASSERT_EQ(KERN_SUCCESS, kr)
448 << MachErrorMessage(kr, "thread_set_exception_ports");
449
450 kr = other_thread_ports.SetExceptionPort(EXC_MASK_CRASH,
451 local_port,
452 EXCEPTION_STATE_IDENTITY,
453 MACHINE_THREAD_STATE);
454 ASSERT_EQ(KERN_SUCCESS, kr)
455 << MachErrorMessage(kr, "thread_set_exception_ports");
456 }
457 }
458
459 // Regardless of where ExceptionPorts::SetExceptionPort() ran,
460 // ExceptionPorts::GetExceptionPorts() can always be tested out-of-process.
461 {
462 SCOPED_TRACE("task");
463 TestGetExceptionPorts(task_ports, local_port, EXCEPTION_DEFAULT);
464 }
465
466 mach_port_t thread_handler =
467 (set_on_ == kSetOnTaskAndThreads) ? local_port : MACH_PORT_NULL;
468
469 {
470 SCOPED_TRACE("main_thread");
471 TestGetExceptionPorts(main_thread_ports, thread_handler, EXCEPTION_STATE);
472 }
473
474 {
475 SCOPED_TRACE("other_thread");
476 TestGetExceptionPorts(
477 other_thread_ports, thread_handler, EXCEPTION_STATE_IDENTITY);
478 }
479
480 // Let the child process know that everything in the parent process is set
481 // up.
482 c = '\0';
483 rv = WriteFD(WritePipeFD(), &c, 1);
484 ASSERT_EQ(1, rv) << ErrnoMessage("write");
485
486 if (who_crashes_ != kNobodyCrashes) {
487 kern_return_t kr = MachMessageServer::Run(this,
488 local_port,
489 MACH_MSG_OPTION_NONE,
490 MachMessageServer::kOneShot,
491 MachMessageServer::kBlocking,
492 0);
493 EXPECT_EQ(KERN_SUCCESS, kr)
494 << MachErrorMessage(kr, "MachMessageServer::Run");
495
496 EXPECT_TRUE(handled_);
497 }
498
499 // Wait for the child process to exit or terminate, as indicated by it
500 // closing its pipe. This keeps LocalPort() alive in the child as
501 // RemotePort(), for the child’s use in its TestGetExceptionPorts().
502 rv = ReadFD(ReadPipeFD(), &c, 1);
503 ASSERT_EQ(0, rv);
504 }
505
506 virtual void MachMultiprocessChild() override {
507 Child child(this);
508 child.Run();
509 }
510
511 SetType set_type_;
512 SetOn set_on_;
513 WhoCrashes who_crashes_;
514
515 // true if an exception message was handled.
516 bool handled_;
517
518 DISALLOW_COPY_AND_ASSIGN(TestExceptionPorts);
519 };
520
521 volatile int TestExceptionPorts::Child::zero_ = 0;
522
523 TEST(ExceptionPorts, TaskAndThreadExceptionPorts) {
524 struct Testcase {
525 TestExceptionPorts::SetType set_type;
526 TestExceptionPorts::SetOn set_on;
527 TestExceptionPorts::WhoCrashes who_crashes;
528 };
529 const Testcase kTestcases[] = {
530 {TestExceptionPorts::kSetInProcess,
531 TestExceptionPorts::kSetOnTaskOnly,
532 TestExceptionPorts::kNobodyCrashes},
533 {TestExceptionPorts::kSetInProcess,
534 TestExceptionPorts::kSetOnTaskOnly,
535 TestExceptionPorts::kMainThreadCrashes},
536 {TestExceptionPorts::kSetInProcess,
537 TestExceptionPorts::kSetOnTaskOnly,
538 TestExceptionPorts::kOtherThreadCrashes},
539 {TestExceptionPorts::kSetInProcess,
540 TestExceptionPorts::kSetOnTaskAndThreads,
541 TestExceptionPorts::kNobodyCrashes},
542 {TestExceptionPorts::kSetInProcess,
543 TestExceptionPorts::kSetOnTaskAndThreads,
544 TestExceptionPorts::kMainThreadCrashes},
545 {TestExceptionPorts::kSetInProcess,
546 TestExceptionPorts::kSetOnTaskAndThreads,
547 TestExceptionPorts::kOtherThreadCrashes},
548 {TestExceptionPorts::kSetOutOfProcess,
549 TestExceptionPorts::kSetOnTaskOnly,
550 TestExceptionPorts::kNobodyCrashes},
551 {TestExceptionPorts::kSetOutOfProcess,
552 TestExceptionPorts::kSetOnTaskOnly,
553 TestExceptionPorts::kMainThreadCrashes},
554 {TestExceptionPorts::kSetOutOfProcess,
555 TestExceptionPorts::kSetOnTaskOnly,
556 TestExceptionPorts::kOtherThreadCrashes},
557 {TestExceptionPorts::kSetOutOfProcess,
558 TestExceptionPorts::kSetOnTaskAndThreads,
559 TestExceptionPorts::kNobodyCrashes},
560 {TestExceptionPorts::kSetOutOfProcess,
561 TestExceptionPorts::kSetOnTaskAndThreads,
562 TestExceptionPorts::kMainThreadCrashes},
563 {TestExceptionPorts::kSetOutOfProcess,
564 TestExceptionPorts::kSetOnTaskAndThreads,
565 TestExceptionPorts::kOtherThreadCrashes},
566 };
567
568 for (size_t index = 0; index < arraysize(kTestcases); ++index) {
569 const Testcase& testcase = kTestcases[index];
570 SCOPED_TRACE(
571 base::StringPrintf("index %zu, set_type %d, set_on %d, who_crashes %d",
572 index,
573 testcase.set_type,
574 testcase.set_on,
575 testcase.who_crashes));
576
577 TestExceptionPorts test_exception_ports(
578 testcase.set_type, testcase.set_on, testcase.who_crashes);
579 test_exception_ports.Run();
580 }
581 }
582
583 TEST(ExceptionPorts, HostExceptionPorts) {
584 // ExceptionPorts isn’t expected to work as non-root. Just do a quick test to
585 // make sure that TargetTypeName() returns the right string, and that the
586 // underlying host_get_exception_ports() function appears to be called by
587 // looking for a KERN_INVALID_ARGUMENT return value. Or, on the off chance
588 // that the test is being run as root, just look for KERN_SUCCESS.
589 // host_set_exception_ports() is not tested, because if the test were running
590 // as root and the call succeeded, it would have global effects.
591
592 base::mac::ScopedMachSendRight host(mach_host_self());
593 ExceptionPorts explicit_host_ports(ExceptionPorts::kTargetTypeHost, host);
594 EXPECT_EQ("host", explicit_host_ports.TargetTypeName());
595
596 std::vector<ExceptionPorts::ExceptionHandler> handlers;
597 kern_return_t kr = explicit_host_ports.GetExceptionPorts(
598 ExcMaskAll() | EXC_MASK_CRASH, &handlers);
599 if (geteuid() == 0) {
600 EXPECT_EQ(KERN_SUCCESS, kr);
601 } else {
602 EXPECT_EQ(KERN_INVALID_ARGUMENT, kr);
603 }
604
605 ExceptionPorts implicit_host_ports(ExceptionPorts::kTargetTypeHost,
606 MACH_PORT_NULL);
607 EXPECT_EQ("host", implicit_host_ports.TargetTypeName());
608
609 kr = implicit_host_ports.GetExceptionPorts(ExcMaskAll() | EXC_MASK_CRASH,
610 &handlers);
611 if (geteuid() == 0) {
612 EXPECT_EQ(KERN_SUCCESS, kr);
613 } else {
614 EXPECT_EQ(KERN_INVALID_ARGUMENT, kr);
615 }
616 }
617
618 } // namespace
OLDNEW
« util/mach/exception_ports.cc ('K') | « util/mach/exception_ports.cc ('k') | util/util.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698