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

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

Issue 993613004: Fix ExceptionPorts.TaskAndThreadExceptionPorts under better compiler optimization (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 5 years, 9 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 | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with 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 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 if (expect_port != MACH_PORT_NULL) { 100 if (expect_port != MACH_PORT_NULL) {
101 EXPECT_TRUE(found); 101 EXPECT_TRUE(found);
102 } else { 102 } else {
103 EXPECT_FALSE(found); 103 EXPECT_FALSE(found);
104 } 104 }
105 } 105 }
106 106
107 class TestExceptionPorts : public MachMultiprocess, 107 class TestExceptionPorts : public MachMultiprocess,
108 public UniversalMachExcServer::Interface { 108 public UniversalMachExcServer::Interface {
109 public: 109 public:
110 // Which entities to set exception ports for.
111 enum SetOn {
112 kSetOnTaskOnly = 0,
113 kSetOnTaskAndThreads,
114 };
115
110 // Where to call ExceptionPorts::SetExceptionPort() from. 116 // Where to call ExceptionPorts::SetExceptionPort() from.
111 enum SetType { 117 enum SetType {
112 // Call it from the child process on itself. 118 // Call it from the child process on itself.
113 kSetInProcess = 0, 119 kSetInProcess = 0,
114 120
115 // Call it from the parent process on the child. 121 // Call it from the parent process on the child.
116 kSetOutOfProcess, 122 kSetOutOfProcess,
117 }; 123 };
118 124
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. 125 // Which thread in the child process is expected to crash.
126 enum WhoCrashes { 126 enum WhoCrashes {
127 kNobodyCrashes = 0, 127 kNobodyCrashes = 0,
128 kMainThreadCrashes, 128 kMainThreadCrashes,
129 kOtherThreadCrashes, 129 kOtherThreadCrashes,
130 }; 130 };
131 131
132 TestExceptionPorts(SetType set_type, SetOn set_on, WhoCrashes who_crashes) 132 TestExceptionPorts(SetOn set_on, SetType set_type, WhoCrashes who_crashes)
133 : MachMultiprocess(), 133 : MachMultiprocess(),
134 UniversalMachExcServer::Interface(), 134 UniversalMachExcServer::Interface(),
135 set_on_(set_on),
135 set_type_(set_type), 136 set_type_(set_type),
136 set_on_(set_on),
137 who_crashes_(who_crashes), 137 who_crashes_(who_crashes),
138 handled_(false) {} 138 handled_(false) {}
139 139
140 SetOn set_on() const { return set_on_; }
140 SetType set_type() const { return set_type_; } 141 SetType set_type() const { return set_type_; }
141 SetOn set_on() const { return set_on_; }
142 WhoCrashes who_crashes() const { return who_crashes_; } 142 WhoCrashes who_crashes() const { return who_crashes_; }
143 143
144 // UniversalMachExcServer::Interface: 144 // UniversalMachExcServer::Interface:
145 145
146 virtual kern_return_t CatchMachException( 146 virtual kern_return_t CatchMachException(
147 exception_behavior_t behavior, 147 exception_behavior_t behavior,
148 exception_handler_t exception_port, 148 exception_handler_t exception_port,
149 thread_t thread, 149 thread_t thread,
150 task_t task, 150 task_t task,
151 exception_type_t exception, 151 exception_type_t exception,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 EXPECT_EQ(EXC_CRASH, exception); 184 EXPECT_EQ(EXC_CRASH, exception);
185 EXPECT_EQ(2u, code_count); 185 EXPECT_EQ(2u, code_count);
186 186
187 // The exception and code_count checks above would ideally use ASSERT_EQ so 187 // The exception and code_count checks above would ideally use ASSERT_EQ so
188 // that the next conditional would not be necessary, but ASSERT_* requires a 188 // that the next conditional would not be necessary, but ASSERT_* requires a
189 // function returning type void, and the interface dictates otherwise here. 189 // function returning type void, and the interface dictates otherwise here.
190 if (exception == EXC_CRASH && code_count >= 1) { 190 if (exception == EXC_CRASH && code_count >= 1) {
191 int signal; 191 int signal;
192 ExcCrashRecoverOriginalException(code[0], nullptr, &signal); 192 ExcCrashRecoverOriginalException(code[0], nullptr, &signal);
193 193
194 // The child crashed with a division by zero, which shows up as SIGFPE. 194 // The child crashed with __builtin_trap(), which shows up as SIGILL.
195 // This was chosen because it’s unlikely to be generated by testing or 195 EXPECT_EQ(SIGILL, signal);
196 // assertion failures.
197 EXPECT_EQ(SIGFPE, signal);
198 196
199 SetExpectedChildTermination(kTerminationSignal, signal); 197 SetExpectedChildTermination(kTerminationSignal, signal);
200 } 198 }
201 199
202 return ExcServerSuccessfulReturnValue(behavior, false); 200 return ExcServerSuccessfulReturnValue(behavior, false);
203 } 201 }
204 202
205 private: 203 private:
206 class Child { 204 class Child {
207 public: 205 public:
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 } 317 }
320 318
321 // If this thread is the one that crashes, do it. 319 // If this thread is the one that crashes, do it.
322 if (test_exception_ports_->who_crashes() == kOtherThreadCrashes) { 320 if (test_exception_ports_->who_crashes() == kOtherThreadCrashes) {
323 Crash(); 321 Crash();
324 } 322 }
325 323
326 return nullptr; 324 return nullptr;
327 } 325 }
328 326
329 // Crashes by performing a division by zero. The assignment is present to 327 static void Crash() {
330 // avoid optimizing zero_ out entirely by making it appear that its value 328 __builtin_trap();
331 // might change. 329 }
332 static void Crash() { zero_ = 1 / zero_; }
333 330
334 // The parent object. 331 // The parent object.
335 TestExceptionPorts* test_exception_ports_; // weak 332 TestExceptionPorts* test_exception_ports_; // weak
336 333
337 // The “other” thread. 334 // The “other” thread.
338 pthread_t thread_; 335 pthread_t thread_;
339 336
340 // The main thread waits on this for the other thread to start up and 337 // The main thread waits on this for the other thread to start up and
341 // perform its own initialization. 338 // perform its own initialization.
342 Semaphore init_semaphore_; 339 Semaphore init_semaphore_;
343 340
344 // The child thread waits on this for the parent thread to indicate that the 341 // The child thread waits on this for the parent thread to indicate that the
345 // child can test its exception ports and possibly crash, as appropriate. 342 // child can test its exception ports and possibly crash, as appropriate.
346 Semaphore crash_semaphore_; 343 Semaphore crash_semaphore_;
347 344
348 // Always zero. Crash() divides by this in order to trigger a crash. This is
349 // structured as a static volatile int to ward off aggressive compiler
350 // optimizations.
351 static volatile int zero_;
352
353 DISALLOW_COPY_AND_ASSIGN(Child); 345 DISALLOW_COPY_AND_ASSIGN(Child);
354 }; 346 };
355 347
356 // MachMultiprocess: 348 // MachMultiprocess:
357 349
358 void MachMultiprocessParent() override { 350 void MachMultiprocessParent() override {
359 // Wait for the child process to be ready. It needs to have all of its 351 // Wait for the child process to be ready. It needs to have all of its
360 // threads set up before proceeding if in kSetOutOfProcess mode. 352 // threads set up before proceeding if in kSetOutOfProcess mode.
361 char c; 353 char c;
362 CheckedReadFile(ReadPipeHandle(), &c, 1); 354 CheckedReadFile(ReadPipeHandle(), &c, 1);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 } 432 }
441 433
442 // Let the child process know that everything in the parent process is set 434 // Let the child process know that everything in the parent process is set
443 // up. 435 // up.
444 c = '\0'; 436 c = '\0';
445 CheckedWriteFile(WritePipeHandle(), &c, 1); 437 CheckedWriteFile(WritePipeHandle(), &c, 1);
446 438
447 if (who_crashes_ != kNobodyCrashes) { 439 if (who_crashes_ != kNobodyCrashes) {
448 UniversalMachExcServer universal_mach_exc_server(this); 440 UniversalMachExcServer universal_mach_exc_server(this);
449 441
442 const mach_msg_timeout_t kTimeoutMs = 50;
450 kern_return_t kr = 443 kern_return_t kr =
451 MachMessageServer::Run(&universal_mach_exc_server, 444 MachMessageServer::Run(&universal_mach_exc_server,
452 local_port, 445 local_port,
453 MACH_MSG_OPTION_NONE, 446 MACH_MSG_OPTION_NONE,
454 MachMessageServer::kOneShot, 447 MachMessageServer::kOneShot,
455 MachMessageServer::kReceiveLargeError, 448 MachMessageServer::kReceiveLargeError,
456 kMachMessageTimeoutWaitIndefinitely); 449 kTimeoutMs);
457 EXPECT_EQ(KERN_SUCCESS, kr) 450 EXPECT_EQ(KERN_SUCCESS, kr)
458 << MachErrorMessage(kr, "MachMessageServer::Run"); 451 << MachErrorMessage(kr, "MachMessageServer::Run");
459 452
460 EXPECT_TRUE(handled_); 453 EXPECT_TRUE(handled_);
461 } 454 }
462 455
463 // Wait for the child process to exit or terminate, as indicated by it 456 // Wait for the child process to exit or terminate, as indicated by it
464 // closing its pipe. This keeps LocalPort() alive in the child as 457 // closing its pipe. This keeps LocalPort() alive in the child as
465 // RemotePort(), for the child’s use in its TestGetExceptionPorts(). 458 // RemotePort(), for the child’s use in its TestGetExceptionPorts().
466 CheckedReadFileAtEOF(ReadPipeHandle()); 459 CheckedReadFileAtEOF(ReadPipeHandle());
467 } 460 }
468 461
469 void MachMultiprocessChild() override { 462 void MachMultiprocessChild() override {
470 Child child(this); 463 Child child(this);
471 child.Run(); 464 child.Run();
472 } 465 }
473 466
467 SetOn set_on_;
474 SetType set_type_; 468 SetType set_type_;
475 SetOn set_on_;
476 WhoCrashes who_crashes_; 469 WhoCrashes who_crashes_;
477 470
478 // true if an exception message was handled. 471 // true if an exception message was handled.
479 bool handled_; 472 bool handled_;
480 473
481 DISALLOW_COPY_AND_ASSIGN(TestExceptionPorts); 474 DISALLOW_COPY_AND_ASSIGN(TestExceptionPorts);
482 }; 475 };
483 476
484 volatile int TestExceptionPorts::Child::zero_ = 0; 477 TEST(ExceptionPorts, TaskExceptionPorts_SetInProcess_NoCrash) {
478 TestExceptionPorts test_exception_ports(
479 TestExceptionPorts::kSetOnTaskOnly,
480 TestExceptionPorts::kSetInProcess,
481 TestExceptionPorts::kNobodyCrashes);
482 test_exception_ports.Run();
483 }
485 484
486 TEST(ExceptionPorts, TaskAndThreadExceptionPorts) { 485 TEST(ExceptionPorts, TaskExceptionPorts_SetInProcess_MainThreadCrash) {
487 struct Testcase { 486 TestExceptionPorts test_exception_ports(
488 TestExceptionPorts::SetType set_type; 487 TestExceptionPorts::kSetOnTaskOnly,
489 TestExceptionPorts::SetOn set_on; 488 TestExceptionPorts::kSetInProcess,
490 TestExceptionPorts::WhoCrashes who_crashes; 489 TestExceptionPorts::kMainThreadCrashes);
491 }; 490 test_exception_ports.Run();
492 const Testcase kTestcases[] = { 491 }
493 {TestExceptionPorts::kSetInProcess,
494 TestExceptionPorts::kSetOnTaskOnly,
495 TestExceptionPorts::kNobodyCrashes},
496 {TestExceptionPorts::kSetInProcess,
497 TestExceptionPorts::kSetOnTaskOnly,
498 TestExceptionPorts::kMainThreadCrashes},
499 {TestExceptionPorts::kSetInProcess,
500 TestExceptionPorts::kSetOnTaskOnly,
501 TestExceptionPorts::kOtherThreadCrashes},
502 {TestExceptionPorts::kSetInProcess,
503 TestExceptionPorts::kSetOnTaskAndThreads,
504 TestExceptionPorts::kNobodyCrashes},
505 {TestExceptionPorts::kSetInProcess,
506 TestExceptionPorts::kSetOnTaskAndThreads,
507 TestExceptionPorts::kMainThreadCrashes},
508 {TestExceptionPorts::kSetInProcess,
509 TestExceptionPorts::kSetOnTaskAndThreads,
510 TestExceptionPorts::kOtherThreadCrashes},
511 {TestExceptionPorts::kSetOutOfProcess,
512 TestExceptionPorts::kSetOnTaskOnly,
513 TestExceptionPorts::kNobodyCrashes},
514 {TestExceptionPorts::kSetOutOfProcess,
515 TestExceptionPorts::kSetOnTaskOnly,
516 TestExceptionPorts::kMainThreadCrashes},
517 {TestExceptionPorts::kSetOutOfProcess,
518 TestExceptionPorts::kSetOnTaskOnly,
519 TestExceptionPorts::kOtherThreadCrashes},
520 {TestExceptionPorts::kSetOutOfProcess,
521 TestExceptionPorts::kSetOnTaskAndThreads,
522 TestExceptionPorts::kNobodyCrashes},
523 {TestExceptionPorts::kSetOutOfProcess,
524 TestExceptionPorts::kSetOnTaskAndThreads,
525 TestExceptionPorts::kMainThreadCrashes},
526 {TestExceptionPorts::kSetOutOfProcess,
527 TestExceptionPorts::kSetOnTaskAndThreads,
528 TestExceptionPorts::kOtherThreadCrashes},
529 };
530 492
531 for (size_t index = 0; index < arraysize(kTestcases); ++index) { 493 TEST(ExceptionPorts, TaskExceptionPorts_SetInProcess_OtherThreadCrash) {
532 const Testcase& testcase = kTestcases[index]; 494 TestExceptionPorts test_exception_ports(
533 SCOPED_TRACE( 495 TestExceptionPorts::kSetOnTaskOnly,
534 base::StringPrintf("index %zu, set_type %d, set_on %d, who_crashes %d", 496 TestExceptionPorts::kSetInProcess,
535 index, 497 TestExceptionPorts::kOtherThreadCrashes);
536 testcase.set_type, 498 test_exception_ports.Run();
537 testcase.set_on, 499 }
538 testcase.who_crashes));
539 500
540 TestExceptionPorts test_exception_ports( 501 TEST(ExceptionPorts, TaskAndThreadExceptionPorts_SetInProcess_NoCrash) {
541 testcase.set_type, testcase.set_on, testcase.who_crashes); 502 TestExceptionPorts test_exception_ports(
542 test_exception_ports.Run(); 503 TestExceptionPorts::kSetOnTaskAndThreads,
543 } 504 TestExceptionPorts::kSetInProcess,
505 TestExceptionPorts::kNobodyCrashes);
506 test_exception_ports.Run();
507 }
508
509 TEST(ExceptionPorts, TaskAndThreadExceptionPorts_SetInProcess_MainThreadCrash) {
510 TestExceptionPorts test_exception_ports(
511 TestExceptionPorts::kSetOnTaskAndThreads,
512 TestExceptionPorts::kSetInProcess,
513 TestExceptionPorts::kMainThreadCrashes);
514 test_exception_ports.Run();
515 }
516
517 TEST(ExceptionPorts,
518 TaskAndThreadExceptionPorts_SetInProcess_OtherThreadCrash) {
519 TestExceptionPorts test_exception_ports(
520 TestExceptionPorts::kSetOnTaskAndThreads,
521 TestExceptionPorts::kSetInProcess,
522 TestExceptionPorts::kOtherThreadCrashes);
523 test_exception_ports.Run();
524 }
525
526 TEST(ExceptionPorts, TaskExceptionPorts_SetOutOfProcess_NoCrash) {
527 TestExceptionPorts test_exception_ports(
528 TestExceptionPorts::kSetOnTaskOnly,
529 TestExceptionPorts::kSetOutOfProcess,
530 TestExceptionPorts::kNobodyCrashes);
531 test_exception_ports.Run();
532 }
533
534 TEST(ExceptionPorts, TaskExceptionPorts_SetOutOfProcess_MainThreadCrash) {
535 TestExceptionPorts test_exception_ports(
536 TestExceptionPorts::kSetOnTaskOnly,
537 TestExceptionPorts::kSetOutOfProcess,
538 TestExceptionPorts::kMainThreadCrashes);
539 test_exception_ports.Run();
540 }
541
542 TEST(ExceptionPorts, TaskExceptionPorts_SetOutOfProcess_OtherThreadCrash) {
543 TestExceptionPorts test_exception_ports(
544 TestExceptionPorts::kSetOnTaskOnly,
545 TestExceptionPorts::kSetOutOfProcess,
546 TestExceptionPorts::kOtherThreadCrashes);
547 test_exception_ports.Run();
548 }
549
550 TEST(ExceptionPorts, TaskAndThreadExceptionPorts_SetOutOfProcess_NoCrash) {
551 TestExceptionPorts test_exception_ports(
552 TestExceptionPorts::kSetOnTaskAndThreads,
553 TestExceptionPorts::kSetOutOfProcess,
554 TestExceptionPorts::kNobodyCrashes);
555 test_exception_ports.Run();
556 }
557
558 TEST(ExceptionPorts,
559 TaskAndThreadExceptionPorts_SetOutOfProcess_MainThreadCrash) {
560 TestExceptionPorts test_exception_ports(
561 TestExceptionPorts::kSetOnTaskAndThreads,
562 TestExceptionPorts::kSetOutOfProcess,
563 TestExceptionPorts::kMainThreadCrashes);
564 test_exception_ports.Run();
565 }
566
567 TEST(ExceptionPorts,
568 TaskAndThreadExceptionPorts_SetOutOfProcess_OtherThreadCrash) {
569 TestExceptionPorts test_exception_ports(
570 TestExceptionPorts::kSetOnTaskAndThreads,
571 TestExceptionPorts::kSetOutOfProcess,
572 TestExceptionPorts::kOtherThreadCrashes);
573 test_exception_ports.Run();
544 } 574 }
545 575
546 TEST(ExceptionPorts, HostExceptionPorts) { 576 TEST(ExceptionPorts, HostExceptionPorts) {
547 // ExceptionPorts isn’t expected to work as non-root. Just do a quick test to 577 // ExceptionPorts isn’t expected to work as non-root. Just do a quick test to
548 // make sure that TargetTypeName() returns the right string, and that the 578 // make sure that TargetTypeName() returns the right string, and that the
549 // underlying host_get_exception_ports() function appears to be called by 579 // underlying host_get_exception_ports() function appears to be called by
550 // looking for a KERN_INVALID_ARGUMENT return value. Or, on the off chance 580 // looking for a KERN_INVALID_ARGUMENT return value. Or, on the off chance
551 // that the test is being run as root, just look for KERN_SUCCESS. 581 // that the test is being run as root, just look for KERN_SUCCESS.
552 // host_set_exception_ports() is not tested, because if the test were running 582 // host_set_exception_ports() is not tested, because if the test were running
553 // as root and the call succeeded, it would have global effects. 583 // as root and the call succeeded, it would have global effects.
(...skipping 20 matching lines...) Expand all
574 if (geteuid() == 0) { 604 if (geteuid() == 0) {
575 EXPECT_TRUE(rv); 605 EXPECT_TRUE(rv);
576 } else { 606 } else {
577 EXPECT_FALSE(rv); 607 EXPECT_FALSE(rv);
578 } 608 }
579 } 609 }
580 610
581 } // namespace 611 } // namespace
582 } // namespace test 612 } // namespace test
583 } // namespace crashpad 613 } // namespace crashpad
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698