CrashTest.cpp 3.1 KB

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