分析核心转储与堆栈损坏
Analyzing core dump with stack corrupted
我目前正在调试我的c++应用程序中的一个核心。客户报告了一个SEGFAULT
核心,其中包含以下线程列表:
...Other threads go above here
3 Thread 0xf73a2b70 (LWP 2120) 0x006fa430 in __kernel_vsyscall ()
2 Thread 0x2291b70 (LWP 2212) 0x006fa430 in __kernel_vsyscall ()
* 1 Thread 0x218fb70 (LWP 2210) 0x00000000 in ?? ()
让我困惑的是线程崩溃了,它指向0x00000000
。如果我尝试检查回溯,我得到:
Thread 1 (Thread 0x1eeeb70 (LWP 27156)):
#0 0x00000000 in ?? ()
#1 0x00281da7 in SomeClass1::_someKnownMethod1 (this=..., elem=...) at path_to_cpp_file:line_number
#2 0x0028484d in SomeClass2::_someKnownMethod2 (this=..., stream=..., stanza=...) at path_to_cpp_file:line_number
#3 0x002958b2 in SomeClass3::_someKnownMethod3 (this=..., stream=..., elem=...) at path_to_cpp_file:line_number
我为编辑道歉-这是保密协议的限制。
显然,顶部框架是未知的。我的第一个猜测是PC
寄存器被一些堆栈覆盖损坏。
我已经尝试在我的本地部署中通过提供在Frame #1
中看到的相同调用来再现这个问题,但是崩溃从未发生。
众所周知,这些内核很难调试?但是有没有人能告诉我应该尝试什么呢?
更新 0x00281d8b <+171>: mov edx,DWORD PTR [ebp+0x8]
0x00281d8e <+174>: mov ecx,DWORD PTR [ebp+0xc]
0x00281d91 <+177>: mov eax,DWORD PTR [edx+0x8]
0x00281d94 <+180>: mov edx,DWORD PTR [eax]
0x00281d96 <+182>: mov DWORD PTR [esp+0x8],ecx
0x00281d9a <+186>: mov ecx,DWORD PTR [ebp+0x8]
0x00281d9d <+189>: mov DWORD PTR [esp],eax
0x00281da0 <+192>: mov DWORD PTR [esp+0x4],ecx
0x00281da4 <+196>: call DWORD PTR [edx+0x14]
=> 0x00281da7 <+199>: mov ebx,DWORD PTR [ebp-0xc]
0x00281daa <+202>: mov esi,DWORD PTR [ebp-0x8]
0x00281dad <+205>: mov edi,DWORD PTR [ebp-0x4]
0x00281db0 <+208>: mov esp,ebp
0x00281db2 <+210>: pop ebp
0x00281db3 <+211>: ret
0x00281db4 <+212>: lea esi,[esi+eiz*1+0x0]
…应该是来自Frame #0
的那个,但从拆卸来看,这没有什么意义。这就像程序已经崩溃,而从Frame #1
返回,但为什么我看到无效的Frame #0
?还是这个框架拆件属于onPacket
函数?
更新# 2:
(gdb) p/x $edx
$5 = 0x1deb664
(gdb) print _listener
$6 = (jax::MyClass &) @0xf6dbf6c4: {_vptr.MyClass= 0x1deb664}
扩展Hayt的评论,因为堆栈的其余部分看起来很好,我怀疑在框架#1中出现了问题;考虑下面这个(显然不正确的)程序,它生成了类似的堆栈跟踪:
int main() {
void (*foo)() = 0;
foo();
return 0;
}
堆栈跟踪:
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x000000000040056a in main ()
如果frame 1在源代码级别上没有意义,您可以尝试拆卸frame 1。选择该帧后,disass $pc
将显示整个函数的反汇编,=>
指示返回地址(在调用第0帧之后的指令)。
在空函数指针解引用的情况下,调用第0帧的指令可能涉及一个简单的寄存器解引用,在这种情况下,您希望了解该寄存器如何获得空值。在某些情况下,在disass
命令中包含/m
可能会有所帮助,尽管由于指令边界和源行边界之间的区别,它可能会引起混淆。省略/m
更有可能显示一个有意义的返回地址。
更新的反汇编中的=>
(没有/m
)是有意义的。在除第0帧之外的任何帧中,pc
值(=>
在反汇编中所指向的值)表示当下一个编号最低的帧返回时将执行的指令(由于崩溃,在本例中没有发生)。第1帧中的pc
值不是崩溃时pc
寄存器的值,而是call
指令压入堆栈的保存的pc
值。一种方法是比较第0帧x/a $sp
和第1帧x/i $pc
的输出。
这种反汇编的一种解释是edx
是某个对象,[edx+0x14]
指向它的虚函数表。虚表可能以空指针结束的一种方式是内存分配问题,对内存块的引用已经过期,该内存块已被释放,随后被其合法所有者(分配该块的下一段代码)覆盖。如果其中任何一个适用于这里,它可以以任何一种方式工作(帧1中的代码可能是罪魁祸首,也可能是受害者)。内存可能被不正确的内容覆盖还有其他原因,但双分配可能是一个很好的开始。
检查第1帧中edx
引用的对象的内容可能是有意义的,看看除了可能是不正确的虚函数表之外,是否还有其他异常。print
命令和x
命令(在gdb中)都可以用于此。根据disass/m
的输出(在撰写本文时,仅在问题的编辑历史中可见),我对edx
引用的对象的最佳猜测是_listener
,但最好通过进一步研究反汇编来确认这一点(这里的摘录似乎不包括确定edx
值的指令)。
另请参见gdb can't access memory address error(在其中一个注释中),其中rogue unmap未映射的内存用于一些其他线程的堆栈,并且内核转储很难使用而崩溃。
- 将大双精度转换为无符号 int 期间堆栈损坏
- 程序终止时堆栈损坏?
- 为什么我的visual c++在堆栈损坏的情况下没有触发堆栈损坏错误
- 调试堆栈损坏问题
- 如何在退出时修复OpenGL堆栈损坏
- OpenCV C++:声明一个新变量会导致堆栈损坏
- 使用 sscanf 堆栈损坏
- C#到C代码P/调用多个std:字符串声明导致堆栈损坏
- 填充数组会导致数组周围的堆栈损坏
- 试图计算fibonacci(n)的变量“f”周围的堆栈损坏
- C++-如何在程序退出时找到堆/堆栈损坏的源
- 链表实现的堆栈损坏
- 可视化C++映射迭代和堆栈损坏
- 在 c++ 中 int 数组周围堆栈损坏错误
- 测试《毁灭战士3》堆栈实现时堆栈损坏
- 如何知道析构函数中的堆栈损坏来自何处
- 在c++中添加int数组时,试图找出堆栈损坏的问题
- 用错误的“”调用构造函数;这个“;指针.这是堆栈损坏吗
- GetCPUDescriptorHandleForHeapStart堆栈损坏
- memcpy之后堆栈损坏