堆栈溢出的Segfault

时间:2008-09-17 08:43:48

标签: linux segmentation-fault

为什么linux内核会在堆栈溢出时生成段错误?当c中的alloca或临时数组的fortran创建溢出时,这会使调试变得非常棘手。当然,运行时可能会产生更有用的错误。

6 个答案:

答案 0 :(得分:41)

您实际上可以使用信号处理程序捕获堆栈溢出的条件。

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

  • 使用sigaction为SIGSEGV(segfault)设置信号处理程序,为此设置SO_ONSTACK标志。这指示内核在传递信号时使用备用堆栈。

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

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

答案 1 :(得分:7)

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

代码:

char *x = alloca(100);
char y = x[150];
当您尝试超出x的界限时,CPU无法真正评估

你可以点击完全相同的地址:

char y = *((char*)(0xdeadbeef));
顺便说一句,我不鼓励使用alloca,因为堆栈往往比堆更有限(使用malloc代替)。

答案 2 :(得分:5)

堆栈溢出是一个分段错误。就像你已经打破了你最初分配的内存界限一样。有限大小的堆栈,你已经超过了它。您可以在wikipedia

了解更多相关信息

此外,我过去为项目做过的一件事就是将自己的信号处理程序写入segfault(查看手册页信号(2))。我经常抓住信号并写出“致命错误已经发生”到控制台。我做了一些关于检查点标志和调试的东西。

为了调试段错误,您可以在GDB中运行程序。例如,以下C程序将是段错误的:     #segfault.c     #包括     #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行有一个分段错误。当然,有更复杂的方法来处理堆栈溢出和其他内存错误,但这就足够了。

答案 3 :(得分:1)

只需使用Valgrind即可。它会以极其严谨的精确性指出你所有的内存分配错误。

答案 4 :(得分:0)

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

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

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

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

答案 5 :(得分:0)

有些评论很有帮助,但问题不在于内存分配错误。那就是代码中没有错误。在fortran中,运行时在堆栈上分配临时值是非常麻烦的。这样的命令如 写(FP)的x,y和z 可以触发是段错误而没有警告。对于英特尔Fortran编译器的技术支持说,运行时库无法打印更有用的消息。但是,如果米格尔是正确的,那么他应该可以这样做。非常感谢。剩下的问题是我如何首先找到seg故障的地址,并弄清楚它是否来自堆栈溢出或其他问题。

对于发现此问题的其他人,有一个编译器标志,它将临时变量放在堆上的特定大小之上。