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

时间:2018-03-09 03:14:16

标签: c++ c debugging stack-overflow

我在捕获信号时使用以下代码打印调用堆栈。但它似乎不适用于堆栈溢出错误。经过一些实验,我发现这个问题可能是由backtrace的调用造成的。我该如何解决?

#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;
}

1 个答案:

答案 0 :(得分:0)

处理由处理程序捕获的堆栈溢出的常用解决方案是使用非常编译器特定的代码在循环中进行回溯。换句话说,没有函数调用包括printf("signal: %d\n", sig);

预防措施限制了回溯量。

signal_handler()的一部分,以不同方式处理事件,检测到重入signal_handler()。也许使用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;
}

通常,答案非常依赖于编译器。