В некоторых кодах есть странные случайные ошибки в коде, вызывающие виртуальные функции-члены.Segfault происходит приблизительно в среднем один раз в вызовах по 30 тыс.
Я использую виртуальные методы для реализации шаблона шаблонного метода.
Строка кода, в которой это происходит, является первой строкой
GenericDevice::updateValue()
{
...
double tmpValue=getValue();
Value=tmpValue;
...
}
с
class GenericDevice
{
public:
void updateValue();
void print(string& result);
...
protected:
virtual double getValue()const=0;
...
private:
std::atomic<double> Value;
...
}
Класс GenericDevice предоставляется позже путем загрузки динамической библиотеки во время выполнения
class SpecializedDeviced : public
{
...
virtual double getValue()const final;
...
}
Я смог получить coredump, когда возникла проблема, и посмотрел код сборки:
0x55cd3ef036f4 GenericDevice::updateValue()+92 mov -0x38(%rbp),%rax
0x55cd3ef036f8 GenericDevice::updateValue()+96 mov (%rax),%rax
0x55cd3ef036fb GenericDevice::updateValue()+99 add $0x40,%rax
0x55cd3ef036ff GenericDevice::updateValue()+103 mov (%rax),%rax
0x55cd3ef03702 GenericDevice::updateValue()+106 mov -0x38(%rbp),%rdx
0x55cd3ef03706 GenericDevice::updateValue()+110 mov %rdx,%rdi
0x55cd3ef03709 GenericDevice::updateValue()+113 callq *%rax
0x55cd3ef0370b <GenericDevice::updateValue()+115> movq %xmm0,%rax
0x55cd3ef03710 <GenericDevice::updateValue()+120> mov %rax,-0x28(%rbp)
0x55cd3ef03714 <GenericDevice::updateValue()+124> mov -0x38(%rbp),%rax
0x55cd3ef03718 <GenericDevice::updateValue()+128> lea 0x38(%rax),%rdx
0x55cd3ef0371c <GenericDevice::updateValue()+132> mov -0x28(%rbp),%rax
0x55cd3ef03720 <GenericDevice::updateValue()+136> mov %rax,-0x40(%rbp)
0x55cd3ef03724 <GenericDevice::updateValue()+140> movsd -0x40(%rbp),%xmm0
Ожидается, что segfault произошла в 0x55cd3ef03709 GenericDevice :: updateValue () + 113,
where
#0 0x000055cd3ef0370a in MyNamespace::GenericDevice::updateValue (this=0x55cd40586698) at ../src/GenericDevice.cpp:22
#1 0x000055cd3ef038d2 in MyNamespace::GenericDevice::print (this=0x55cd40586698,result="REDACTED"...) at ../src/GenericDevice.cpp:50
...
Функция GenericDevice :: updateValue () была вызвана так, как и предполагалось
<GenericDevice::print(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)+301> callq 0x55cd3ef03698 <GenericDevice::updateValue()>
Причина, по которой rax установлен в 0x0.
Register group: general
rax 0x0 0
rbx 0x5c01b8a2 1543616674
rcx 0x2 2
rdx 0x28 40
rsi 0x2 2
rdi 0x55cd40586630 94340036191792
rbp 0x7ffe39086e60 0x7ffe39086e60
rsp 0x7ffe39086e20 0x7ffe39086e20
r8 0x7fbb06e7e8a0 140441251473568
r9 0x3 3
r10 0x33 51
r11 0x206 518
r12 0x55cd3ef19438 94340012676152
r13 0x7ffe39089010 140729855283216
r14 0x0 0
r15 0x0 0
rip 0x55cd3ef0370a 0x55cd3ef0370a<GenericDevice::updateValue()+114> eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
Выполняя вычисления из отрывка сборки, я могу подтвердить, что код сборки и используемые данные соответствуют ожидаемому вызову виртуальной функции и начинаются с правильных данных:
этот указатель объекта используется
(gdb) x /g $rbp-0x38
0x7ffe39086e28: 0x000055cd40586698
(gdb) p this
$1 = (GenericDevice * const) 0x55cd40586698
указатель на vtable правильный (первый элемент * this)
(gdb) x 0x000055cd40586698
0x55cd40586698: 0x00007fbb070c1aa0
(gdb) info vtbl this
vtable for 'GenericDevice' @ 0x7fbb070c1aa0 (subobject @ 0x55cd40586698):
vtable содержит адрес метода, который мы ищем.
(gdb) info vtbl this
vtable for 'GenericDevice' @ 0x7fbb070c1aa0 (subobject @ 0x55cd40586698):
...
[8]: 0x7fbb06e7bf50 non-virtual thunk to MyNamespace::SpecializedDevice::getValue() const.
используется правильное смещение для vtable
(gdb) x 0x00007fbb070c1aa0+0x40
0x7fbb070c1ae0 <_ZTVN12MyNamespace11SpecializedDeviceE+168>: 0x00007fbb06e7bf50
Заключение на данный момент: пошаговое выполнение кода ассемблера позволило проверить правильность данных и инструкций.
- Использовались правильные данные: повреждение памяти может быть исключено.
- Инструкции по сборке кажутся правильными: ошибка кодирования / компиляции может быть исключена
- vtable выглядит нормально: ошибка при загрузке библиотеки во время выполнения может быть исключена: также функция обычно работает нормально десятки тысяч раз.
Пожалуйста, не стесняйтесь указывать на любые ошибки в моих рассуждениях.
Тем не менее значение в регистре rax равно нулю вместо ожидаемого 0x7fbb070c1ae0
- Может ли это указывать на аппаратную ошибку в одном (редко используемом) ядре процессора?Объяснил бы редкий и случайный случай, но я ожидал бы проблем с другими программами и ОС также.
Модель процессора - процессор Intel® Core (TM) i7-4770 @ 3,40 ГГц
Заранее спасибо!
Обновление: я нашел $Маркер RIP
0x55cd3ef0370a MyNamespace::GenericDevice::updateValue()+114 shlb 0x48(%rsi)
Сборка, показанная gdb, похоже, меняется после прокрутки.Вот почему я не увидел маркер с первой попытки.После запуска GDB и ввода макета asm я получаю:
>0x55cd3ef0370a <MyNamespace::GenericDevicer::updateValue()+114> shlb 0x48(%rsi)
0x55cd3ef0370d <MyNamespace::GenericDevicer::updateValue()+117> movd %mm0,%eax
0x55cd3ef03710 <MyNamespace::GenericDevicer::updateValue()+120> mov %rax,-0x28(%rbp)
0x55cd3ef03714 <MyNamespace::GenericDevicer::updateValue()+124> mov -0x38(%rbp),%rax
0x55cd3ef03718 <MyNamespace::GenericDevicer::updateValue()+128> lea 0x38(%rax),%rdx
0x55cd3ef0371c <MyNamespace::GenericDevicer::updateValue()+132> mov -0x28(%rbp),%rax
0x55cd3ef03720 <MyNamespace::GenericDevicer::updateValue()+136> mov %rax,-0x40(%rbp)
0x55cd3ef03724 <MyNamespace::GenericDevicer::updateValue()+140> movsd -0x40(%rbp),%xmm0
...
После прокрутки AMS в GDB я получаю код, отправленный в исходном вопросе.Код в исходном вопросе соответствует коду из исполняемого файла.Приведенный выше код частично отклоняется от исполняемого файла.
Инструкция shlb не имеет смысла для меня.Не удалось найти инструкцию даже в Руководстве разработчика программного обеспечения для архитектуры Intel® 64 и IA-32 .Ближайший матч был зы.