如何报告分段错误?

时间:2012-09-03 01:47:12

标签: c++ bash ubuntu segmentation-fault

我只是想知道如何报告分段错误。

  • 这个过程就会死掉,显然它无法报告。
  • 除非进程传递信号,否则shell不会确定无疑,这可能不是必然的。
  • 操作系统可能会做某事,但我不确定如何。

其中哪一个报告了细分错误(只是一个例子),以及如何?

4 个答案:

答案 0 :(得分:3)

  

这个过程就会死掉,显然它无法报告。

这实际上是假的。 可以安装SIGSEGV处理程序来替换默认处理程序,它只是转储核心和死亡。预加载库可以捕获分段违规并使用可用的有限设施通知系统上运行的另一个进程,然后退出。

答案 1 :(得分:2)

如果查看函数wait() or waitpid(),您会发现退出状态中的一个位表示核心转储。 POSIX规范提到WIFSIGNALED [sic]和WTERMSIG以获取终止进程的信号。 POSIX规范没有提到它,但是在Mac OS X(10.7.4)上,有一个WCOREDUMP()宏来测试核心文件是否被创建。

答案 2 :(得分:2)

您可以使用this之类的代码调用GDB命令来转储调用跟踪:

void BacktraceOnSegv() {
  struct sigaction action = {};
  action.sa_handler = DumpBacktrace;
  if (sigaction(SIGSEGV, &action, NULL) < 0) {
    perror("sigaction(SEGV)");
  }
}

void DumpBacktrace(int) {
  pid_t dying_pid = getpid();
  pid_t child_pid = fork();
  if (child_pid < 0) {
    perror("fork() while collecting backtrace:");
  } else if (child_pid == 0) {
    char buf[1024];
    sprintf(buf, "gdb -p %d -batch -ex bt 2>/dev/null | "
            "sed '0,/<signal handler/d'", dying_pid);
    const char* argv[] = {"sh", "-c", buf, NULL};
    execve("/bin/sh", (char**)argv, NULL);
    _exit(1);
  } else {
    waitpid(child_pid, NULL, 0);
  }
  _exit(1);
}

Here是一种支持更多平台的实现。

答案 3 :(得分:1)

好的,首先,当CPU尝试访问进程无权访问的地址时,会发生分段错误。在最低级别,内存映射的实现必须检测到,这通常会产生中断。内核接收到该中断,并有一个其他代码段的地址表,每个代码段都用于处理该中断。

当内核收到该中断时,它会将其转换为特定值(我很模糊,因为具体细节因硬件架构和内核实现而异)。 SIGSEGV通常定义为值11,但确切的值并不重要;它在signal.h中定义。

此时,信号值被传递到内核中的另一个表,该表包含“信号处理程序”的地址。其中一个处理程序位于由SIGSEGV表示的偏移处。除非您已经做了一些改变它的事情,否则该地址通常是导致核心转储的例程,假设适当的限制允许,但您可以用您自己的例程地址替换它,这可以做任何您喜欢的事情。