【问题标题】:Debugging segfault with no apparent cause in gdb?在 gdb 中调试没有明显原因的段错误?
【发布时间】:2025-12-31 08:40:06
【问题描述】:

gdb 报告说我的 C 代码在 malloc() 的某个地方崩溃了,所以我将我的代码与 Electric Fence 相关联,以查明内存错误的实际来源。现在我的代码更早出现了段错误,但 gdb 的输出更加令人困惑:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x30026b00 (LWP 4003)]
0x10007c30 in simulated_status (axis=1, F=0x300e7fa8, B=0x1003a520, A=0x3013b000, p=0x1003b258, XS=0x3013b000)
    at ccp_gch.c:799

编辑:完整的回溯:

(gdb) bt
#0  0x10007c30 in simulated_status (axis=1, F=0x300e7fa8, B=0x1003a520, A=0x3013b000, p=0x1003b258, XS=0x3013b000)
    at ccp_gch.c:799
#1  0x10007df8 in execute_QUERY (F=0x300e7fa8, B=0x1003a520, iData=0x7fb615c0) at ccp_gch.c:836
#2  0x10009680 in execute_DATA_cmd (P=0x300e7fa8, B=0x7fb615cc, R_type=0x7fb615d0, iData=0x7fb615c0)
    at ccp_gch.c:1581
#3  0x10015bd8 in do_volley (client=13) at session.c:76
#4  0x10015ef4 in do_dialogue (v=12, port=2007) at session.c:149
#5  0x10016350 in do_session (starting_port=2007, ports=1) at session.c:245
#6  0x100056e4 in main (argc=2, argv=0x7fb618f4) at main.c:271

相关代码(因原因稍作修改):

796  static uint32_t simulated_status(
797      unsigned axis, struct foo *F, struct bar *B, struct Axis *A, BAZ *p, uint64_t *XS)
798  {
799      uint32_t result = A->status;
800      *XS = get_status(axis);
801      if (!some_function(p)) {
802          ...

要检查的显而易见的事情是A->status 是否是有效内存,但确实如此。删除分配会将段错误推送到第 800 行,删除 that 分配会导致 if 块中的其他一些分配出现段错误。看起来好像访问传递给函数的参数或写入局部变量是导致段错误的原因,但根据 gdb,一切都指向有效内存。

我该如何解释?我以前从未见过这样的事情,所以任何正确方向的建议/指针都将不胜感激。我正在使用 GNU gdb 6.8-debian、Electric Fence 2.1,并在 PowerPC 405 上运行(uname 报告 Linux powerpmac 2.6.30.3 #24 [...] ppc GNU/Linux)。

【问题讨论】:

  • 你有另一台机器要测试吗?您的代码是否在 gdb 之外出现段错误?
  • 你可能更早地被堆栈粉碎而不知道它。过去我在索引数据越界时遇到过类似的问题,但后来的代码行实际上触发了中断(即:free() 调用有效内存)。您可以尝试使用零优化和强大的堆栈保护器 (CCOPTS+=-O0 DEBUG=-g -fstack-protector-strong) 来编译您的代码吗?如果您正在破坏堆栈,这应该会导致您的程序比平时更快地崩溃,并且应该指出您在代码中践踏内存的位置。
  • 副手,Valgrind 报告了什么?看起来您正在破坏您的堆或您真正访问的内存,这些内存可能看起来有效但实际上已经被释放。而且那个调用堆栈还没有接近完整。 *其余部分是什么样的(一​​直到初始线程过程)?当然,您可能完全没有被具有大量自动装置的激活堆栈占用的堆栈空间。我认为这会很快恢复。
  • 我可以在另一台机器上进行测试,但它连接到真实(而且价格昂贵!)硬件,我想避免在上面运行错误代码。根据日志文件,我的代码在 gdb 之外发生了段错误。
  • @Fraxtil:能否分享一下 GDB 遇到 seg fault 时命令“shell cat /proc/PID/maps”和“info r”的输出。

标签: c debugging gdb segmentation-fault electric-fence


【解决方案1】:

我猜,但您的症状类似于堆栈溢出情况下可能发生的情况。 cmets 中的-fstack-protector 建议在这里是正确的。我建议也添加-fstack-check 选项。

如果 SEGV 是由于写入保护堆栈的保护页而发生的,那么 gdb 中的 info registersinfo frame 将有助于确认是否是这种情况。

【讨论】:

    最近更新 更多