Эти фиктивные адреса (0x00000002 и т. П.) На самом деле являются значениями ПК, а не значениями SP. Теперь, когда вы получаете этот тип SEGV с поддельным (очень маленьким) адресом ПК, в 99% случаев это происходит из-за ложного указателя на функцию. Обратите внимание, что виртуальные вызовы в C ++ реализуются через указатели на функции, поэтому любая проблема с виртуальным вызовом может проявляться аналогичным образом.
Инструкция непрямого вызова просто помещает ПК после вызова в стек, а затем устанавливает для ПК целевое значение (в данном случае фальшивое), поэтому, если это равно , что произошло, вы можете легко отменить это вручную выталкивая ПК из стека. В 32-битном коде x86 вы просто делаете:
(gdb) set $pc = *(void **)$esp
(gdb) set $esp = $esp + 4
С 64-битным кодом x86 вам нужно
(gdb) set $pc = *(void **)$rsp
(gdb) set $rsp = $rsp + 8
Тогда вы сможете выполнить bt
и выяснить, где на самом деле код.
В остальное 1% времени ошибка будет связана с перезаписью стека, обычно из-за переполнения массива, хранящегося в стеке. В этом случае вы могли бы получить больше ясности в ситуации, используя такой инструмент, как valgrind