backtrace()与signal处理:程序崩溃时打印堆栈
如何利用 execinfo.h 的 backtrace()/backtrace_symbols() 函数在程序崩溃时打印调用堆栈?结合 signal handler(SIGSEGV/SIGABRT)实现优雅的错误报告。
回答
孤独的心
使用 <execinfo.h> 在信号处理器中打印堆栈:
#include <execinfo.h>
#include <signal.h>
#include <unistd.h>
#include <iostream>
void handler(int sig) {
void* buffer[100];
int nptrs = backtrace(buffer, 100);
// 方案1: 输出到 stderr
backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
// 方案2: 获取符号名后自定义输出
char** symbols = backtrace_symbols(buffer, nptrs);
for (int i = 0; i < nptrs; ++i) {
std::cerr << symbols[i] << '\n';
}
free(symbols);
_exit(128 + sig); // 安全退出
}
int main() {
signal(SIGSEGV, handler);
signal(SIGABRT, handler);
// ... 触发崩溃
}
注意事项:
- 信号处理器中只能调用 async-signal-safe 函数。
backtrace_symbols不是 safe 的(malloc),但backtrace_symbols_fd是 safe 的。 - 编译时加
-rdynamic保留符号名。 - 生产环境推荐
libunwind获取更精确的栈信息。 - 可选使用
addr2line将地址转为文件名/行号。
现代方案:C++23 std::stacktrace 或使用 boost::stacktrace。