简体   繁体   English

调用堆栈溢出时如何打印调用堆栈?

[英]How to print call stack when call stack overflows?

I use the following code to print call stack when catching a signal. 捕获信号时,我使用以下代码来打印调用堆栈。 But it seems that it doesn't work for stack overflow errors. 但似乎它不适用于堆栈溢出错误。 After some experiments, I find this problem may be caused by the call of backtrace . 经过一些实验,我发现此问题可能是由backtrace的调用引起的。 How can I fix it? 我该如何解决?

#include <stdlib.h>
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>

void signal_handler(int sig)
{
  printf("signal: %d\n", sig);

  void* dump_array[256];
  int num = backtrace(dump_array, 256);

  if (num) 
  {
    printf("backtrace rank = %d\n", num);

    char** symbols = backtrace_symbols(dump_array, num);
    if (symbols) 
    {
      for (int i = 0; i < num; i++)
        printf("%s\n", symbols[i]);

      free(symbols);
    }
  }

  exit(-1);
}

void func()
{
  func();
}

int main(void)
{
  stack_t ss = {};
  ss.ss_size = SIGSTKSZ;

  if (!(ss.ss_sp = malloc(SIGSTKSZ)))
  {
    perror("malloc");
    exit(-1);
  }

  if (sigaltstack(&ss, NULL) == -1)
  {
    perror("sigaltstack");
    exit(-1);
  }

  struct sigaction act = {};
  act.sa_handler = signal_handler;
  act.sa_flags = SA_ONSTACK;
  sigfillset(&act.sa_mask);

  if (sigaction(SIGSEGV, &act, NULL) == -1)
    perror("sigaction");

  *(int*)123 = 456; // works
  //func(); // doesn't work

  return 0;
}

A usual solution to handling stack-overflow caught by a handler is to use very compiler specific code to do backtracking in a loop . 处理处理程序捕获的堆栈溢出的常见解决方案是使用非常特定于编译器的代码在循环中进行回溯。 In other words, no function calls including printf("signal: %d\\n", sig); 换句话说,没有函数调用包括printf("signal: %d\\n", sig); .

A precaution limits the amount of back-tracing. 预防措施会限制反向跟踪的数量。

A part of signal_handler() it to handle things differently it a re-entrant signal_handler() is detected. signal_handler()一部分, signal_handler()检测到重入signal_handler()时以不同方式处理事物。 Perhaps use a static int first_time flag. 也许使用static int first_time标志。

void signal_handler(int sig) {
  static int first_time = 0;
  if (first_time == 0) {
    first_time++;
    for (int i = 0; i<max; i++) {
      ... // gather back trace data
    }
  }
  ... // save exit into some place
  exit -1;
}

In general, the answer is very compiler dependent. 通常,答案非常依赖于编译器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM