«Необъяснимый» основной дамп - PullRequest
26 голосов
/ 16 января 2011

Я видел много основных дампов в своей жизни, но этот один меня озадачил.

Контекст:

  • многопоточная программа Linux / x86_64, работающая в кластере из AMD Barcelona ЦП
  • код, который вылетает, выполняется лот
  • запуск 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() появился какой-то гремлин и увеличил %rip на 4.

Правдоподобные объяснения?

Ответы [ 2 ]

31 голосов
/ 06 апреля 2013

Таким образом, маловероятно, что кажется, что мы столкнулись с реальной ошибкой ЦП.

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).
4 голосов
/ 16 января 2011

Я однажды видел сбой "недопустимого кода операции" прямо в середине инструкции.Я работал над портом Linux.Короче говоря, Linux вычитает из указателя инструкций, чтобы перезапустить системный вызов, и в моем случае это происходило дважды (если два сигнала поступали одновременно).

Так что это один из возможных виновников: ядровозиться с указателем вашей инструкции.В вашем случае может быть какая-то другая причина.

Имейте в виду, что иногда процессор воспринимает данные, которые он обрабатывает, как инструкцию, даже если это не так.Таким образом, процессор, возможно, выполнил «инструкцию» в 0x17bd9fa, а затем перешел в 0x17bd9fd и затем сгенерировал недопустимое исключение кода операции.(Я только что сделал это число, но эксперименты с дизассемблером могут показать вам, где процессор мог «войти» в поток инструкций.)

Удачной отладки!

...