CodeWalk

backtrace()与signal处理:程序崩溃时打印堆栈

作者:孤独的心 · 2026-05-30 12:55

如何利用 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);
    
    // ... 触发崩溃
}

注意事项

  1. 信号处理器中只能调用 async-signal-safe 函数。backtrace_symbols 不是 safe 的(malloc),但 backtrace_symbols_fd 是 safe 的。
  2. 编译时加 -rdynamic 保留符号名。
  3. 生产环境推荐 libunwind 获取更精确的栈信息。
  4. 可选使用 addr2line 将地址转为文件名/行号。

现代方案:C++23 std::stacktrace 或使用 boost::stacktrace