linux “无法解释”的核心转储

qni6mghb  于 2023-01-04  发布在  Linux
关注(0)|答案(2)|浏览(199)

我一生中见过许多核心转储,但这一次让我不知所措。
背景:

  • 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。
合理的解释?

oxcyiej7

oxcyiej71#

因此,虽然看起来不太可能,但我们似乎遇到了一个真正的CPU bug。
https://web.archive.org/web/20130228081435/http://support.amd.com/us/Processor_TechDocs/41322_10h_Rev_Gd.pdf包含勘误表#721:

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

描述

在一组非常具体和详细的内部时序条件下,处理器可能会在一长串压入和/或近调用指令,或者一长串弹出和/或近返回指令之后错误地更新堆栈指针。处理器必须处于64位模式,才会出现此错误。

对系统的潜在影响

堆栈指针值以大约1024的值正向或负向跳转。此不正确的堆栈指针会导致不可预知的程序或系统行为,通常表现为程序异常或崩溃(例如,#GP或#UD)。

建议的变通方案

系统软件可设置MSRC001_1029 [0]= 1b。

neskvpey

neskvpey2#

我曾经看到一个"非法操作码"在指令执行过程中崩溃。我当时正在处理一个Linux端口。长话短说,Linux从指令指针中减去,以便重新启动一个系统调用,在我的例子中,这种情况发生了两次(如果两个信号同时到达)。
所以这是一个可能的罪魁祸首:内核在摆弄你的指令指针。2在你的情况下可能有一些其他的原因。
请记住,有时处理器会将正在处理的数据理解为指令,即使它不应该理解为指令。因此,处理器可能在0x17bd9fa执行了"指令",然后移到0x17bd9fd,然后生成了非法操作码异常。(这个数字是我瞎编的,但是用反汇编器进行实验可以显示处理器可能"进入"指令流的位置。)
调试愉快!

相关问题