error_handler.cpp 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // SuperTux
  2. // Copyright (C) 2020 A. Semphris <semphris@protonmail.com>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "supertux/error_handler.hpp"
  17. // execinfo.h as a built-in libc feature is exclusive to glibc as of 2020.
  18. // On FreeBSD and musl systems, an external libexecinfo is available, but
  19. // it has to be explicitly linked into the final executable.
  20. // This is a *libc* feature, not a compiler one; furthermore, it's possible
  21. // to verify its availability in CMakeLists.txt, if one is so inclined.
  22. #ifdef __GLIBC__
  23. #include <execinfo.h>
  24. #include <signal.h>
  25. #include <unistd.h>
  26. #endif
  27. bool ErrorHandler::m_handing_error = false;
  28. void
  29. ErrorHandler::set_handlers()
  30. {
  31. #ifdef __GLIBC__
  32. signal(SIGSEGV, handle_error);
  33. signal(SIGABRT, handle_error);
  34. #endif
  35. }
  36. [[ noreturn ]] void
  37. ErrorHandler::handle_error(int sig)
  38. {
  39. if (m_handing_error)
  40. {
  41. // Error happened again while handling another segfault. Abort now.
  42. close_program();
  43. }
  44. else
  45. {
  46. m_handing_error = true;
  47. // Do not use external stuff (like log_fatal) to limit the risk of causing
  48. // another error, which would restart the handler again.
  49. fprintf(stderr, "\nError: signal %d:\n", sig);
  50. print_stack_trace();
  51. close_program();
  52. }
  53. }
  54. void
  55. ErrorHandler::print_stack_trace()
  56. {
  57. #ifdef __GLIBC__
  58. void *array[127];
  59. size_t size;
  60. // Get void*'s for all entries on the stack.
  61. size = backtrace(array, 127);
  62. // Print out all the frames to stderr.
  63. backtrace_symbols_fd(array, static_cast<int>(size), STDERR_FILENO);
  64. #endif
  65. }
  66. [[ noreturn ]] void
  67. ErrorHandler::close_program()
  68. {
  69. exit(10);
  70. }
  71. /* EOF */