【问题标题】:"Unexplainable" core dump“无法解释”的核心转储
【发布时间】:2011-06-09 21:13:32
【问题描述】:

我一生中见过很多核心转储,但这一次让我难过。

上下文:

  • AMD Barcelona CPU 集群上运行的多线程 Linux/x86_64 程序
  • 崩溃的代码被执行了很多
  • 在负载下运行 1000 个程序实例(完全相同的优化二进制文件)每小时会产生 1-2 次崩溃
  • 崩溃发生在不同的机器上(但机器本身非常相似)
  • 崩溃看起来都一样(相同的确切地址,相同的调用堆栈)

以下是崩溃的详细信息:

Program terminated with signal 11, Segmentation fault.
#0  0x00000000017bd9fd in Foo()
(gdb) x/i $pc
=> 0x17bd9fd <_Z3Foov+349>: rex.RB orb $0x8d,(%r15)

(gdb) x/6i $pc-12
0x17bd9f1 <_Z3Foov+337>:    mov    (%rbx),%eax
0x17bd9f3 <_Z3Foov+339>:    mov    %rbx,%rdi
0x17bd9f6 <_Z3Foov+342>:    callq  *0x70(%rax)
0x17bd9f9 <_Z3Foov+345>:    cmp    %eax,%r12d
0x17bd9fc <_Z3Foov+348>:    mov    %eax,-0x80(%rbp)
0x17bd9ff <_Z3Foov+351>:    jge    0x17bd97e <_Z3Foov+222>

您会注意到崩溃发生在0x17bd9fc 的指令中间,这是在从0x17bd9f6 的调用返回到虚函数之后。

当我检查虚拟表时,我发现它没有以任何方式损坏:

(gdb) x/a $rbx
0x2ab094951f80: 0x3f8c550 <_ZTI4Foo1+16>
(gdb) x/a 0x3f8c550+0x70
0x3f8c5c0 <_ZTI4Foo1+128>:  0x2d3d7b0 <_ZN4Foo13GetEv>

并且它指向这个微不足道的函数(正如通过查看源代码所预期的那样):

(gdb) disas 0x2d3d7b0
Dump of assembler code for function _ZN4Foo13GetEv:
   0x0000000002d3d7b0 <+0>: push   %rbp
   0x0000000002d3d7b1 <+1>: mov    0x70(%rdi),%eax
   0x0000000002d3d7b4 <+4>: mov    %rsp,%rbp
   0x0000000002d3d7b7 <+7>: leaveq 
   0x0000000002d3d7b8 <+8>: retq   
End of assembler dump.

此外,当我查看Foo1::Get() 应该返回的返回地址时:

(gdb) x/a $rsp-8
0x2afa55602048: 0x17bd9f9 <_Z3Foov+345>

我看到它指向了正确的指令,所以好像在从Foo1::Get() 返回期间,出现了一些 gremlin,并将 %rip 增加了 4。

合理的解释?

【问题讨论】:

  • 你有没有发现是什么原因造成的?如果是这样,我很想知道它是什么!
  • @us2012 我相信我们确实找到了原因。看我的回答。

标签: linux segmentation-fault x86-64


【解决方案1】:

因此,尽管看起来不太可能,但我们似乎遇到了真正的 CPU 错误。

http://support.amd.com/us/Processor_TechDocs/41322_10h_Rev_Gd.pdf 有错误 #721:

721 处理器可能错误地更新堆栈指针

说明

Under a highly specific and detailed set of internal timing conditions,
the processor may incorrectly update the stack pointer after a long series
of push and/or near-call instructions, or a long series of pop 
and/or near-return instructions. The processor must be in 64-bit mode for
this erratum to occur.

对系统的潜在影响

The stack pointer value jumps by a value of approximately 1024, either in
the positive or negative direction.
This incorrect stack pointer causes unpredictable program or system behavior,
usually observed as a program exception or crash (for example, a #GP or #UD).

【讨论】:

  • 哎哟。它实际上是否是一个“高度具体”的条件 - 即,您是否设法通过稍微更改在问题点生成的代码来解决它?
  • @us2012 我们的代码和编译器在不断变化,问题突然消失了……只是在 2 年后在一个完全不相关的可执行文件中再次发生。
【解决方案2】:

我曾经在指令中间看到“非法操作码”崩溃。我正在研究Linux端口。长话短说,Linux 从指令指针中减去以重新启动系统调用,在我的例子中,这发生了两次(如果两个信号同时到达)。

所以这是一个可能的罪魁祸首:内核摆弄你的指令指针。您的情况可能还有其他原因。

请记住,有时处理器会将其正在处理的数据理解为指令,即使它不应该如此。所以处理器可能已经执行了 0x17bd9fa 处的“指令”,然后移动到 0x17bd9fd,然后生成了一个非法操作码异常。 (我刚刚计算了这个数字,但是使用反汇编程序进行试验可以向您展示处理器可能“进入”指令流的位置。)

调试愉快!

【讨论】:

  • 我已经考虑过信号,但是有几个“罢工”对他们来说是原因: 1. 请注意,这段代码周围没有任何系统调用; 2. 该线程不应该接收任何异步信号; 3. 如果是信号引起的,你如何解释所有崩溃程序中exact相同地址上发生的崩溃?
  • 我没有暗示你的问题可能是信号。 (这只是导致我的问题的端口中的错误。)我的观点是完全在您的程序之外的因素 - 例如内核错误 - 可能会导致这个问题。另一件可能弄乱指令指针的事情是异常处理。
猜你喜欢
  • 1970-01-01
  • 2015-05-12
  • 2013-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多