diff --git a/util/mach/exception_ports_test.cc b/util/mach/exception_ports_test.cc index 43fb0257..8948eae7 100644 --- a/util/mach/exception_ports_test.cc +++ b/util/mach/exception_ports_test.cc @@ -107,6 +107,12 @@ void TestGetExceptionPorts(const ExceptionPorts& exception_ports, class TestExceptionPorts : public MachMultiprocess, public UniversalMachExcServer::Interface { public: + // Which entities to set exception ports for. + enum SetOn { + kSetOnTaskOnly = 0, + kSetOnTaskAndThreads, + }; + // Where to call ExceptionPorts::SetExceptionPort() from. enum SetType { // Call it from the child process on itself. @@ -116,12 +122,6 @@ class TestExceptionPorts : public MachMultiprocess, kSetOutOfProcess, }; - // Which entities to set exception ports for. - enum SetOn { - kSetOnTaskOnly = 0, - kSetOnTaskAndThreads, - }; - // Which thread in the child process is expected to crash. enum WhoCrashes { kNobodyCrashes = 0, @@ -129,16 +129,16 @@ class TestExceptionPorts : public MachMultiprocess, kOtherThreadCrashes, }; - TestExceptionPorts(SetType set_type, SetOn set_on, WhoCrashes who_crashes) + TestExceptionPorts(SetOn set_on, SetType set_type, WhoCrashes who_crashes) : MachMultiprocess(), UniversalMachExcServer::Interface(), - set_type_(set_type), set_on_(set_on), + set_type_(set_type), who_crashes_(who_crashes), handled_(false) {} - SetType set_type() const { return set_type_; } SetOn set_on() const { return set_on_; } + SetType set_type() const { return set_type_; } WhoCrashes who_crashes() const { return who_crashes_; } // UniversalMachExcServer::Interface: @@ -191,10 +191,8 @@ class TestExceptionPorts : public MachMultiprocess, int signal; ExcCrashRecoverOriginalException(code[0], nullptr, &signal); - // The child crashed with a division by zero, which shows up as SIGFPE. - // This was chosen because it’s unlikely to be generated by testing or - // assertion failures. - EXPECT_EQ(SIGFPE, signal); + // The child crashed with __builtin_trap(), which shows up as SIGILL. + EXPECT_EQ(SIGILL, signal); SetExpectedChildTermination(kTerminationSignal, signal); } @@ -326,10 +324,9 @@ class TestExceptionPorts : public MachMultiprocess, return nullptr; } - // Crashes by performing a division by zero. The assignment is present to - // avoid optimizing zero_ out entirely by making it appear that its value - // might change. - static void Crash() { zero_ = 1 / zero_; } + static void Crash() { + __builtin_trap(); + } // The parent object. TestExceptionPorts* test_exception_ports_; // weak @@ -345,11 +342,6 @@ class TestExceptionPorts : public MachMultiprocess, // child can test its exception ports and possibly crash, as appropriate. Semaphore crash_semaphore_; - // Always zero. Crash() divides by this in order to trigger a crash. This is - // structured as a static volatile int to ward off aggressive compiler - // optimizations. - static volatile int zero_; - DISALLOW_COPY_AND_ASSIGN(Child); }; @@ -447,13 +439,14 @@ class TestExceptionPorts : public MachMultiprocess, if (who_crashes_ != kNobodyCrashes) { UniversalMachExcServer universal_mach_exc_server(this); + const mach_msg_timeout_t kTimeoutMs = 50; kern_return_t kr = MachMessageServer::Run(&universal_mach_exc_server, local_port, MACH_MSG_OPTION_NONE, MachMessageServer::kOneShot, MachMessageServer::kReceiveLargeError, - kMachMessageTimeoutWaitIndefinitely); + kTimeoutMs); EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "MachMessageServer::Run"); @@ -471,8 +464,8 @@ class TestExceptionPorts : public MachMultiprocess, child.Run(); } - SetType set_type_; SetOn set_on_; + SetType set_type_; WhoCrashes who_crashes_; // true if an exception message was handled. @@ -481,66 +474,103 @@ class TestExceptionPorts : public MachMultiprocess, DISALLOW_COPY_AND_ASSIGN(TestExceptionPorts); }; -volatile int TestExceptionPorts::Child::zero_ = 0; +TEST(ExceptionPorts, TaskExceptionPorts_SetInProcess_NoCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskOnly, + TestExceptionPorts::kSetInProcess, + TestExceptionPorts::kNobodyCrashes); + test_exception_ports.Run(); +} -TEST(ExceptionPorts, TaskAndThreadExceptionPorts) { - struct Testcase { - TestExceptionPorts::SetType set_type; - TestExceptionPorts::SetOn set_on; - TestExceptionPorts::WhoCrashes who_crashes; - }; - const Testcase kTestcases[] = { - {TestExceptionPorts::kSetInProcess, - TestExceptionPorts::kSetOnTaskOnly, - TestExceptionPorts::kNobodyCrashes}, - {TestExceptionPorts::kSetInProcess, - TestExceptionPorts::kSetOnTaskOnly, - TestExceptionPorts::kMainThreadCrashes}, - {TestExceptionPorts::kSetInProcess, - TestExceptionPorts::kSetOnTaskOnly, - TestExceptionPorts::kOtherThreadCrashes}, - {TestExceptionPorts::kSetInProcess, - TestExceptionPorts::kSetOnTaskAndThreads, - TestExceptionPorts::kNobodyCrashes}, - {TestExceptionPorts::kSetInProcess, - TestExceptionPorts::kSetOnTaskAndThreads, - TestExceptionPorts::kMainThreadCrashes}, - {TestExceptionPorts::kSetInProcess, - TestExceptionPorts::kSetOnTaskAndThreads, - TestExceptionPorts::kOtherThreadCrashes}, - {TestExceptionPorts::kSetOutOfProcess, - TestExceptionPorts::kSetOnTaskOnly, - TestExceptionPorts::kNobodyCrashes}, - {TestExceptionPorts::kSetOutOfProcess, - TestExceptionPorts::kSetOnTaskOnly, - TestExceptionPorts::kMainThreadCrashes}, - {TestExceptionPorts::kSetOutOfProcess, - TestExceptionPorts::kSetOnTaskOnly, - TestExceptionPorts::kOtherThreadCrashes}, - {TestExceptionPorts::kSetOutOfProcess, - TestExceptionPorts::kSetOnTaskAndThreads, - TestExceptionPorts::kNobodyCrashes}, - {TestExceptionPorts::kSetOutOfProcess, - TestExceptionPorts::kSetOnTaskAndThreads, - TestExceptionPorts::kMainThreadCrashes}, - {TestExceptionPorts::kSetOutOfProcess, - TestExceptionPorts::kSetOnTaskAndThreads, - TestExceptionPorts::kOtherThreadCrashes}, - }; +TEST(ExceptionPorts, TaskExceptionPorts_SetInProcess_MainThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskOnly, + TestExceptionPorts::kSetInProcess, + TestExceptionPorts::kMainThreadCrashes); + test_exception_ports.Run(); +} - for (size_t index = 0; index < arraysize(kTestcases); ++index) { - const Testcase& testcase = kTestcases[index]; - SCOPED_TRACE( - base::StringPrintf("index %zu, set_type %d, set_on %d, who_crashes %d", - index, - testcase.set_type, - testcase.set_on, - testcase.who_crashes)); +TEST(ExceptionPorts, TaskExceptionPorts_SetInProcess_OtherThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskOnly, + TestExceptionPorts::kSetInProcess, + TestExceptionPorts::kOtherThreadCrashes); + test_exception_ports.Run(); +} - TestExceptionPorts test_exception_ports( - testcase.set_type, testcase.set_on, testcase.who_crashes); - test_exception_ports.Run(); - } +TEST(ExceptionPorts, TaskAndThreadExceptionPorts_SetInProcess_NoCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskAndThreads, + TestExceptionPorts::kSetInProcess, + TestExceptionPorts::kNobodyCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, TaskAndThreadExceptionPorts_SetInProcess_MainThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskAndThreads, + TestExceptionPorts::kSetInProcess, + TestExceptionPorts::kMainThreadCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, + TaskAndThreadExceptionPorts_SetInProcess_OtherThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskAndThreads, + TestExceptionPorts::kSetInProcess, + TestExceptionPorts::kOtherThreadCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, TaskExceptionPorts_SetOutOfProcess_NoCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskOnly, + TestExceptionPorts::kSetOutOfProcess, + TestExceptionPorts::kNobodyCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, TaskExceptionPorts_SetOutOfProcess_MainThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskOnly, + TestExceptionPorts::kSetOutOfProcess, + TestExceptionPorts::kMainThreadCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, TaskExceptionPorts_SetOutOfProcess_OtherThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskOnly, + TestExceptionPorts::kSetOutOfProcess, + TestExceptionPorts::kOtherThreadCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, TaskAndThreadExceptionPorts_SetOutOfProcess_NoCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskAndThreads, + TestExceptionPorts::kSetOutOfProcess, + TestExceptionPorts::kNobodyCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, + TaskAndThreadExceptionPorts_SetOutOfProcess_MainThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskAndThreads, + TestExceptionPorts::kSetOutOfProcess, + TestExceptionPorts::kMainThreadCrashes); + test_exception_ports.Run(); +} + +TEST(ExceptionPorts, + TaskAndThreadExceptionPorts_SetOutOfProcess_OtherThreadCrash) { + TestExceptionPorts test_exception_ports( + TestExceptionPorts::kSetOnTaskAndThreads, + TestExceptionPorts::kSetOutOfProcess, + TestExceptionPorts::kOtherThreadCrashes); + test_exception_ports.Run(); } TEST(ExceptionPorts, HostExceptionPorts) {