【问题标题】:Program received signal SIGSEGV, Segmentation fault (program runs out of stack.)程序收到信号 SIGSEGV,分段错误(程序用尽堆栈。)
【发布时间】:2013-09-11 21:24:21
【问题描述】:

当我使用 gdb 运行程序时收到此错误消息。错误显示在这一行:

long a = thread_fake(); //in file1.c

我遇到了在单独文件中定义的其他函数的问题,因此我将其简化为仅返回 0 的简单函数。 函数定义为:

long thread_fake(){ //defined in file2.c
    return 0;
}

正如@EmployedRussian 指出的那样,程序似乎用完了堆栈。 valgrind 显示以下错误:

==14711== 144 bytes in 1 blocks are possibly lost in loss record 17 of 32
==14711==    at 0x4025315: calloc (vg_replace_malloc.c:467)
==14711==    by 0x4010CD7: allocate_dtv (dl-tls.c:300)
==14711==    by 0x401146B: _dl_allocate_tls (dl-tls.c:464)
==14711==    by 0x40475C6: pthread_create@@GLIBC_2.1 (allocatestack.c:570)
==14711==    by 0x8050583: tm_main_startup 
==14711==    by 0x8048F6B: main (genome.c:201)
==14711== 144 bytes in 1 blocks are possibly lost in loss record 18 of 32
==14711==    at 0x4025315: calloc (vg_replace_malloc.c:467)
==14711==    by 0x4010CD7: allocate_dtv (dl-tls.c:300)
==14711==    by 0x401146B: _dl_allocate_tls (dl-tls.c:464)
==14711==    by 0x40475C6: pthread_create@@GLIBC_2.1 (allocatestack.c:570)
==14711==    by 0x804DFE3: thread_startup (thread.c:151)
==14711==    by 0x8048F73: main (genome.c:203)

所有创建的线程都加入了相应的 pthread_join 调用。我也尝试了 sgcheck 工具,但它在平台'x86-linux'上不起作用。请帮忙。

bt 命令的完整输出:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x406e8b70 (LWP 19416)]
sequencer_run (argPtr=0x89fce00) at sequencer.c:251
251 a = thread_fake();
(gdb) bt
#0  sequencer_run (argPtr=0x89fce00) at sequencer.c:251
#1  0x0804e306 in threadWait (argPtr=0x89dc1f4) at ../lib/thread.c:105
#2  0x4003be99 in start_thread (arg=0x406e8b70) at pthread_create.c:304
#3  0x40253cbe in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130

【问题讨论】:

  • 你是在file1.c还是在它包含的头文件中声明了函数?
  • @n.m.在 file1.c 包含的头文件 file2.h 中
  • @JamesMcLaughlin no..
  • 您写道,使用 gdb 运行程序时会出现此错误。当您在 gdb 之外运行它时会发生这种情况吗?
  • 发布最短的、完整的、可编译的示例来重现错误。

标签: c gdb segmentation-fault


【解决方案1】:

错误显示在这一行:

long a = thread_fake(); //in file1.c

SIGSEGV 可能出现的情况是您的程序已用完堆栈。

使用x/i $pc 检查 GDB 中的实际崩溃指令。

如果指令是PUSH,或者CALL,那么我的猜测就被证实了。

另一种可能性:您已经通过优化编译了代码,而实际的错误指令与它所归属的源代码行几乎没有关系。

更新:

是的,它会打电话给call 0x804e580 <thread_fake>。有什么解决办法?

解决方案是不要用完堆栈。执行 GDB where 命令,然后在导致崩溃的每一帧中,执行 info frame 并查找过大的帧。

不要在堆栈上分配太多数据,或增加堆栈大小 (ulimit -s)。

valgrind 显示以下错误:

那是

  • 不是错误
  • 与您的问题无关

更新2:

如何查看每一帧的大小?

鉴于此:

Stack level 0, frame at 0xffffc248:
...
Stack level 1, frame at 0xffffc250:
...
Stack level 2, frame at 0xffffc2a0:

帧#1 的大小是8 (0xffffc250 - 0xffffc248),帧#2 是80,等等

最终更新:

原来我上面的程序无法测量frame#0的大小,原来是... 61MB!由于存在 humongous 本地数组(正如 Grady Player 正确猜测的那样)。

【讨论】:

  • 这是一个很好的可能性......操作应该寻找类似 int huge[23456678899];不要再这样做了。
  • @EmployedRussian 是的,它会调用 "call 0x804e580 " 有什么解决方案?
  • @EmployedRussian 我还想提一提的是,该程序在单线程上运行良好,但最终在 2 个或更多线程上使用 SIGSEGV..
  • @EmployedRussian 我还检查了 where 和 info frame 的命令。但是我如何检查每个帧的大小。它只是提到了类似-堆栈级别0,0x406e8370处的帧:sequencer_run(sequencer.c:251)中的eip = 0x8049a3c;保存 eip 0x804e476 在 0x406e8390 源语言 c. arglist在0x406e8368,argptr = 0x89fde00当地人在0x406e8368,之前的帧的sp为0x406e8370保存寄存器:EBX在0x406E835C,EBP处0x406E8368,ESI为0x406E8360,EDI在0x406E8364,EIP为0x406E836C span>
  • @ceedee 所以你几乎立即用完了堆栈,几乎没有消耗任何堆栈空间。你究竟是如何创建这个线程的?
猜你喜欢
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多