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

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

Powered by Google App Engine
This is Rietveld 408576698