C ++如何识别SIGNAL 11错误位置

时间:2015-12-07 17:13:15

标签: c++ linux

我正在Linux系统中运行多线程C ++程序 (内核2.6.23)。我的代码是使用G ++ 4.7.4版编译的。

我添加了以下代码来捕获分段错误:

<variable name="StdLayout" 
value="${longdate} | ${level} | ${logger} | ${message:exceptionSeparator= }${exception:format=tostring}" />

主要:

void segFaultHandler(int sig)
{
  void *array[10];
  size_t size;

  size = backtrace(array, 10);
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

运行时,我的程序崩溃了以下输出:

main()
{
    signal(SIGSEGV, segFaultHandler);

    try {

         program code here...

    catch(const std::exception& ex)
    {
        std::cerr << "Error occurred: " << ex.what() << std::endl;
    }
    catch(...)
    {
        std::cerr << "Unknown failure occurred. Possible memory corruption" << std::endl;
    }

    return 0;
}

这不是一个简单的调试,因为我的程序有时会崩溃,所以我需要一个工具来获取崩溃源并修复它。

从给定的输出中,我如何追溯导致崩溃的函数和代码段?

2 个答案:

答案 0 :(得分:3)

您可以使用valgrind找到段错误的来源。如果您使用调试符号编译二进制文件,它将为您提供确切的源位置:

==12834== Invalid write of size 4
==12834==    at 0x4004FD: main (test.cc:3)
==12834==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

答案 1 :(得分:0)

您可以使用谷歌的Address Sanitizer (ASAN)来检测分段错误以及与内存相关的其他常见编程错误(包括释放后的堆使用,缓冲区溢出,缓冲区下溢,释放内存两次,内存泄漏等)。如果检测到错误,它将给出错误发生位置的堆栈跟踪(如果使用-g包含调试符号,则堆栈跟踪可以理解)。

ASAN在编译时链接到您的二进制文件,并在运行时以非常小的开销检查您的堆(代码运行速度慢约2倍)。这比valgrind快得多,并且具有以下优势:它可以在实时环境中运行,并且如果您的用例可以接受2x减速,则会提供有价值的消息。

此外,如果您的分段错误是由上述编程错误之一引起的,那么在代码甚至出现错误之前,它将被ASAN捕获。例如,假设您缓冲溢出,破坏堆的状态。当您稍后转到malloc内存时,malloc seg会因为堆已损坏而出错。即使真正的问题是堆缓冲区溢出,任何信号处理程序都会在此时检测到损坏。 ASAN会在堆缓冲区溢出时为您提供堆栈跟踪。