Serenity Operating System
at master 109 lines 3.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2019-2020, Shannon Booth <shannon.ml.booth@gmail.com> 4 * Copyright (c) 2021, Brian Gianforcaro <bgianf@serenityos.org> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/Assertions.h> 10#include <AK/Platform.h> 11#include <LibTest/CrashTest.h> 12#include <sys/wait.h> 13#include <unistd.h> 14 15#if !defined(AK_OS_MACOS) && !defined(AK_OS_EMSCRIPTEN) 16# include <sys/prctl.h> 17#endif 18 19namespace Test { 20 21Crash::Crash(DeprecatedString test_type, Function<Crash::Failure()> crash_function, int crash_signal) 22 : m_type(move(test_type)) 23 , m_crash_function(move(crash_function)) 24 , m_crash_signal(crash_signal) 25{ 26} 27 28bool Crash::run(RunType run_type) 29{ 30 outln("\x1B[33mTesting\x1B[0m: \"{}\"", m_type); 31 32 if (run_type == RunType::UsingCurrentProcess) { 33 return do_report(m_crash_function()); 34 } else { 35 // Run the test in a child process so that we do not crash the crash program :^) 36 pid_t pid = fork(); 37 if (pid < 0) { 38 perror("fork"); 39 VERIFY_NOT_REACHED(); 40 } else if (pid == 0) { 41#if !defined(AK_OS_MACOS) && !defined(AK_OS_EMSCRIPTEN) 42 if (prctl(PR_SET_DUMPABLE, 0, 0) < 0) 43 perror("prctl(PR_SET_DUMPABLE)"); 44#endif 45 exit((int)m_crash_function()); 46 } 47 48 int status; 49 waitpid(pid, &status, 0); 50 if (WIFEXITED(status)) { 51 return do_report(Failure(WEXITSTATUS(status))); 52 } 53 if (WIFSIGNALED(status)) { 54 int signal = WTERMSIG(status); 55 VERIFY(signal > 0); 56 return do_report(signal); 57 } 58 VERIFY_NOT_REACHED(); 59 } 60} 61 62bool Crash::do_report(Report report) 63{ 64 bool pass = false; 65 if (m_crash_signal == ANY_SIGNAL) { 66 pass = report.has<int>(); 67 } else if (m_crash_signal == 0) { 68 pass = report.has<Failure>() && report.get<Failure>() == Failure::DidNotCrash; 69 } else if (m_crash_signal > 0) { 70 pass = report.has<int>() && report.get<int>() == m_crash_signal; 71 } else { 72 VERIFY_NOT_REACHED(); 73 } 74 75 if (pass) 76 out("\x1B[32mPASS\x1B[0m: "); 77 else 78 out("\x1B[31mFAIL\x1B[0m: "); 79 80 report.visit( 81 [&](Failure const& failure) { 82 switch (failure) { 83 case Failure::DidNotCrash: 84 out("Did not crash"); 85 break; 86 case Failure::UnexpectedError: 87 out("Unexpected error"); 88 break; 89 default: 90 VERIFY_NOT_REACHED(); 91 } 92 }, 93 [&](int const& signal) { 94 out("Terminated with signal {}", signal); 95 }); 96 97 if (!pass) { 98 if (m_crash_signal == ANY_SIGNAL) { 99 out(" while expecting any signal"); 100 } else if (m_crash_signal > 0) { 101 out(" while expecting signal {}", m_crash_signal); 102 } 103 } 104 outln(); 105 106 return pass; 107} 108 109}