Segfault在堆栈溢出

为什么linux内核在堆栈溢出时产生段错误? 当c中的alloca或Fortran创build临时数组溢出时,这可能会使debugging非常尴尬。 当然,运行时可能会产生更有用的错误。

Solutions Collecting From Web of "Segfault在堆栈溢出"

实际上,你可以使用信号处理程序捕捉堆栈溢出的情况。

要做到这一点,你必须做两件事:

  • 使用sigaction设置SIGSEGV(segfault)的信号处理程序,以设置SO_ONSTACK标志。 这指示内核在传送信号时使用另一个堆栈。

  • 调用sigaltstack()来设置SIGSEGV的处理程序将使用的备用堆栈。

然后,当你溢出堆栈时,内核将在交付信号之前切换到备用堆栈。 一旦进入信号处理程序,就可以检查导致故障的地址,并确定是堆栈溢出还是常规故障。

“内核”(实际上不是内核运行你的代码,它是CPU)不知道你的代码是如何引用它不应该触及的内存。 它只知道你试图去做。

代码:

char *x = alloca(100); char y = x[150]; 

当你尝试访问超越x的边界时,不能真正被CPU评估。

您可以用以下方法找到完全相同的地址:

 char y = *((char*)(0xdeadbeef)); 

顺便说一句,我会劝阻使用alloca,因为堆栈往往比堆更有限(使用malloc来代替)。

堆栈溢出是分段错误。 正如你打破了你最初分配的记忆界限一样。 有限大小的堆栈,你已经超过了它。 你可以在维基百科上阅读更多

另外,过去我为项目所做的一件事就是将自己的信号处理程序写入段错误(查看手册页信号(2))。 我通常抓住信号,并写出“致命的错误已经发生”的控制台。 我用检查点标志做了一些更多的事情,并进行了调试。

为了调试段错误,你可以在GDB中运行一个程序。 例如,下面的C程序将会出现段错误:#segfault.c #include #include

 int main() { printf("Starting\n"); void *foo=malloc(1000); memcpy(foo, 0, 100); //this line will segfault exit(0); } 

如果我这样编译它:

 gcc -g -o segfault segfault.c 

然后像这样运行它:

 $ gdb ./segfault GNU gdb 6.7.1 Copyright (C) 2007 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... Using host libthread_db library "/lib/libthread_db.so.1". (gdb) run Starting program: /tmp/segfault Starting Program received signal SIGSEGV, Segmentation fault. 0x4ea43cbc in memcpy () from /lib/libc.so.6 (gdb) bt #0 0x4ea43cbc in memcpy () from /lib/libc.so.6 #1 0x080484cb in main () at segfault.c:8 (gdb) 

我从GDB发现,第8行出现了分段错误。当然,还有更复杂的处理堆栈溢出和其他内存错误的方法,但这样就足够了。

只需使用Valgrind 。 它将以令人难以忍受的严谨性指出你所有的内存分配错误。

堆栈溢出不一定会导致崩溃。 它可能会悄悄地垃圾你的程序的数据,但继续执行。

我不会使用SIGSEGV处理程序kludges,而是修复原来的问题。

如果你想要自动化的帮助,你可以使用gcc的-Wstack-protector选项,它会在运行时发现一些溢出并中止程序。

valgrind适用于动态内存分配错误,但不适用于堆栈错误。

一些评论是有帮助的,但问题不是内存分配错误。 这是代码中没有错误。 在Fortran中,运行时在栈上分配临时值是相当麻烦的。 因此,诸如write(fp)x,y,z的命令可以触发,而不会发出警告。 英特尔Fortran编译器的技术支持表示,运行时库无法打印更有用的消息。 然而,如果米格尔是正确的,那么他应该可以这样做。 非常感谢。 剩下的问题是,我怎样才能先找到seg故障的地址,然后找出是否出现堆栈溢出或其他问题。

对于其他谁发现这个问题有一个编译器的标志,把临时变量超过一定的大小在堆上。