| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e75d2ff commit 66aba44
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -57,53 +57,6 @@ Code from above will output something like this: | |||
| 57 | 57 | [note By default the Stacktrace library is very conservative in methods to decode stacktrace. If your output does not look as fancy as in example from above, see [link stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ] | |
| 58 | 58 | ||
| 59 | 59 | ||
| 60 | - [endsect] | ||
| 61 | - | ||
| 62 | - [section Handle terminates, aborts and Segmentation Faults] | ||
| 63 | - | ||
| 64 | - Segmentation Faults and `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace will significantly improve debugging and fixing. | ||
| 65 | - | ||
| 66 | - `std::terminate` calls `std::abort`, so we need to capture stack traces on Segmentation Faults and Abort signals. | ||
| 67 | - | ||
| 68 | - [warning Writing a signal handler requires high attention! Only a few system calls allowed in signal handlers, so there's no cross platform way to print a stacktrace without a risk of deadlocking. The only way to deal with the problem - [*dump raw stacktrace into file/socket and parse it on program restart].] | ||
| 69 | - | ||
| 70 | - [warning Not all the platforms provide means for even getting stacktrace in async signal safe way. No stack trace will be saved on such platforms. ] | ||
| 71 | - | ||
| 72 | - Let's write a handler to safely dump stacktrace: | ||
| 73 | - | ||
| 74 | - [getting_started_terminate_handlers] | ||
| 75 | - | ||
| 76 | - Registering our handler: | ||
| 77 | - | ||
| 78 | - [getting_started_setup_handlers] | ||
| 79 | - | ||
| 80 | - At program start we check for a file with stacktrace and if it exist - we're writing it in human readable format: | ||
| 81 | - | ||
| 82 | - [getting_started_on_program_restart] | ||
| 83 | - | ||
| 84 | - Now we'll get the following output on `std::terminate` call after the program restarts: | ||
| 85 | - | ||
| 86 | - ``` | ||
| 87 | - Previous run crashed: | ||
| 88 | - 0# 0x00007F2EC0A6A8EF | ||
| 89 | - 1# my_signal_handler(int) at ../example/terminate_handler.cpp:37 | ||
| 90 | - 2# 0x00007F2EBFD84CB0 | ||
| 91 | - 3# 0x00007F2EBFD84C37 | ||
| 92 | - 4# 0x00007F2EBFD88028 | ||
| 93 | - 5# 0x00007F2EC0395BBD | ||
| 94 | - 6# 0x00007F2EC0393B96 | ||
| 95 | - 7# 0x00007F2EC0393BE1 | ||
| 96 | - 8# bar(int) at ../example/terminate_handler.cpp:18 | ||
| 97 | - 9# foo(int) at ../example/terminate_handler.cpp:22 | ||
| 98 | - 10# bar(int) at ../example/terminate_handler.cpp:14 | ||
| 99 | - 11# foo(int) at ../example/terminate_handler.cpp:22 | ||
| 100 | - 12# main at ../example/terminate_handler.cpp:84 | ||
| 101 | - 13# 0x00007F2EBFD6FF45 | ||
| 102 | - 14# 0x0000000000402209 | ||
| 103 | - ``` | ||
| 104 | - | ||
| 105 | - [note Function names from shared libraries may not be decoded due to address space layout randomization. Still better than nothing.] | ||
| 106 | - | ||
| 107 | 60 | [endsect] | |
| 108 | 61 | ||
| 109 | 62 | [section Better asserts] | |
@@ -137,6 +90,42 @@ Backtrace: | |||
| 137 | 90 | ||
| 138 | 91 | Now we do know the steps that led to the assertion and can find the error without debugger. | |
| 139 | 92 | ||
| 93 | + [endsect] | ||
| 94 | + | ||
| 95 | + [section Handle terminates] | ||
| 96 | + | ||
| 97 | + `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace significantly improves debugging and fixing. | ||
| 98 | + | ||
| 99 | + Here's how to write a terminate handler that dumps stacktrace: | ||
| 100 | + | ||
| 101 | + [getting_started_terminate_handlers] | ||
| 102 | + | ||
| 103 | + Here's how to register it: | ||
| 104 | + | ||
| 105 | + [getting_started_setup_terminate_handlers] | ||
| 106 | + | ||
| 107 | + Now we'll get the following output on `std::terminate` call: | ||
| 108 | + | ||
| 109 | + ``` | ||
| 110 | + Previous run crashed: | ||
| 111 | + 0# my_terminate_handler(int) at ../example/terminate_handler.cpp:37 | ||
| 112 | + 1# __cxxabiv1::__terminate(void (*)()) at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:48 | ||
| 113 | + 2# 0x00007F3CE65E5901 in /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | ||
| 114 | + 3# bar(int) at ../example/terminate_handler.cpp:18 | ||
| 115 | + 4# foo(int) at ../example/terminate_handler.cpp:22 | ||
| 116 | + 5# bar(int) at ../example/terminate_handler.cpp:14 | ||
| 117 | + 6# foo(int) at ../example/terminate_handler.cpp:22 | ||
| 118 | + 7# main at ../example/terminate_handler.cpp:84 | ||
| 119 | + 8# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6 | ||
| 120 | + 9# 0x0000000000402209 | ||
| 121 | + ``` | ||
| 122 | + | ||
| 123 | + [warning There's a temptation to write a signal handler that prints the stacktrace on `SIGSEGV` or abort. Unfortunately, there's no cross platform way to do that without a risk of deadlocking. Not all the platforms provide means for even getting stacktrace in async signal safe way. | ||
| 124 | + | ||
| 125 | + Generic recommendation is to *avoid signal handlers, use* platform specific ways to store and decode *core files*. | ||
| 126 | + ] | ||
| 127 | + | ||
| 128 | + | ||
| 140 | 129 | [endsect] | |
| 141 | 130 | ||
| 142 | 131 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -23,25 +23,42 @@ BOOST_NOINLINE void foo(int i) { | |||
| 23 | 23 | ||
| 24 | 24 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 25 | 25 | ||
| 26 | - //[getting_started_terminate_handlers | ||
| 26 | + //[getting_started_signal_handlers | ||
| 27 | 27 | ||
| 28 | 28 | #include <signal.h> // ::signal, ::raise | |
| 29 | 29 | #include <boost/stacktrace.hpp> | |
| 30 | 30 | ||
| 31 | 31 | void my_signal_handler(int signum) { | |
| 32 | 32 | ::signal(signum, SIG_DFL); | |
| 33 | + | ||
| 34 | + // Outputs nothing or trash on majority of platforms | ||
| 33 | 35 | boost::stacktrace::safe_dump_to("./backtrace.dump"); | |
| 36 | + | ||
| 34 | 37 | ::raise(SIGABRT); | |
| 35 | 38 | } | |
| 36 | 39 | //] | |
| 37 | 40 | ||
| 38 | 41 | void setup_handlers() { | |
| 39 | - //[getting_started_setup_handlers | ||
| 42 | + //[getting_started_setup_signel_handlers | ||
| 40 | 43 | ::signal(SIGSEGV, &my_signal_handler); | |
| 41 | 44 | ::signal(SIGABRT, &my_signal_handler); | |
| 42 | 45 | //] | |
| 43 | 46 | } | |
| 44 | 47 | ||
| 48 | + | ||
| 49 | + //[getting_started_terminate_handlers | ||
| 50 | + #include <cstdlib> // std::abort | ||
| 51 | + #include <exception> // std::set_terminate | ||
| 52 | + #include <iostream> // std::cerr | ||
| 53 | + | ||
| 54 | + #include <boost/stacktrace.hpp> | ||
| 55 | + | ||
| 56 | + void my_terminate_handler() { | ||
| 57 | + std::cerr << boost::stacktrace::stacktrace(); | ||
| 58 | + std::abort(); | ||
| 59 | + } | ||
| 60 | + //] | ||
| 61 | + | ||
| 45 | 62 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 46 | 63 | ||
| 47 | 64 | BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8; | |
@@ -92,6 +109,15 @@ inline void copy_and_run(const char* exec_name, char param, bool not_null) { | |||
| 92 | 109 | } | |
| 93 | 110 | } | |
| 94 | 111 | ||
| 112 | + int run_0(const char* /*argv*/[]) { | ||
| 113 | + //[getting_started_setup_terminate_handlers | ||
| 114 | + std::set_terminate(&my_terminate_handler); | ||
| 115 | + //] | ||
| 116 | + foo(5); | ||
| 117 | + return 1; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + | ||
| 95 | 121 | int run_1(const char* /*argv*/[]) { | |
| 96 | 122 | setup_handlers(); | |
| 97 | 123 | foo(5); | |
@@ -300,6 +326,7 @@ int test_inplace() { | |||
| 300 | 326 | ||
| 301 | 327 | int main(int argc, const char* argv[]) { | |
| 302 | 328 | if (argc < 2) { | |
| 329 | + copy_and_run(argv[0], '0', true); | ||
| 303 | 330 | #ifndef BOOST_WINDOWS | |
| 304 | 331 | // We are copying files to make sure that stacktrace printing works independently from executable name | |
| 305 | 332 | copy_and_run(argv[0], '1', true); | |
@@ -314,6 +341,7 @@ int main(int argc, const char* argv[]) { | |||
| 314 | 341 | } | |
| 315 | 342 | ||
| 316 | 343 | switch (argv[1][0]) { | |
| 344 | + case '0': return run_0(argv); | ||
| 317 | 345 | case '1': return run_1(argv); | |
| 318 | 346 | case '2': return run_2(argv); | |
| 319 | 347 | case '3': return run_3(argv); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments