Linux &引用;“无法解释”;堆芯倾卸

Linux &引用;“无法解释”;堆芯倾卸,linux,segmentation-fault,x86-64,Linux,Segmentation Fault,X86 64,在我的生活中,我见过很多核心垃圾场,但这一次让我感到困惑 背景: 在CPU集群上运行的多线程Linux/x86_64程序 崩溃的代码执行了很多次 在负载下运行1000个程序实例(完全相同的优化二进制),每小时会产生1-2次崩溃 崩溃发生在不同的机器上(但机器本身是完全相同的) 所有崩溃看起来都一样(相同的确切地址,相同的调用堆栈) 以下是此次坠机的详细情况: Program terminated with signal 11, Segmentation fault. #0 0x000000

在我的生活中,我见过很多核心垃圾场,但这一次让我感到困惑

背景:

  • 在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>
它指向这个平凡的函数(通过查看源代码可以预期):

我看到它指向了正确的指令,所以就好像在从
Foo1::Get()
返回的过程中,出现了一些小精灵,并将
%rip
增加了4

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

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

请记住,有时处理器会将其处理的数据理解为一条指令,即使它不应该是指令。因此,处理器可能在0x17bd9fa执行了“指令”,然后转到0x17bd9fd,然后生成了非法操作码异常。(我刚刚算出了这个数字,但使用反汇编程序进行实验可以告诉您处理器可能“输入”了指令流的位置。)


调试愉快

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

有勘误表721:

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

描述

对系统的潜在影响


我已经考虑过信号,但有几个“打击”是原因:1。请注意,此代码周围没有系统调用;2.此线程不应接收任何异步信号;3.如果是信号引起的,你如何解释所有崩溃程序中发生在完全相同地址的崩溃?我不认为你的问题可能是信号。(这只是我问题背后的端口错误。)我的观点是,程序完全外部的因素——比如内核错误——可能是导致这个问题的原因。另一件会弄乱指令指针的事情是异常处理。你有没有发现这是什么原因?如果是这样的话,我很想知道那是什么@我相信我们找到了原因。看看我的答案。哎哟。这实际上是一种“高度特定”的情况吗?即,您是否通过稍微更改在问题点生成的代码来修复它?@us2012我们的代码和编译器在不断变化,问题就像它出现一样突然消失。。。2年后,在一个完全不相关的可执行文件中再次发生。
(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.
(gdb) x/a $rsp-8
0x2afa55602048: 0x17bd9f9 <_Z3Foov+345>
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).