Archive

Posts Tagged ‘gdb’

到底是哪个线程导致了crash呢?

December 15th, 2011 No comments

  在linux下调试确实不熟悉,这不?又上当了。

   以前同事告知,当程序crash以后,用gdb打开core文件,第一个引入眼帘线程就是出现异常的那个线程。通常情况下一个where指令就可以让你知道到底是什么位置引起的crash。

  但是今天遇到的问题却有点奇怪。事情是这样的,一个程序在测试环境中crash了。拿到了core文件用gdb打开以后,直接where,出现的call stack如下。(下面的callstack是我随意写的,只是问了说明一下大概情形)

0 memcpy() ...
1 std::string::string()
2 xmlbuild::buildnode()
....

也就是说看起来是在Buildnode函数中调用一个std::string的构造函数的时候出错了。我满以为找到问题了,但是当我看代码的时候就郁闷了。buildnode中调用string的构造函数的传入传输也是一个std::string.用gdb的p命令查看这个std::string instance发现没有异常。奇怪了,要抓狂了。我开始怀疑这个call stack是否准确了,难道gdb坏了。

  经过较长时间的瞎想乱猜,我觉得会不会是我们的程序因为catch了SIGSEGV并且在这个信号的处理函数中做了一些事情(打印一些日志说当前的进程光荣就义了之类的,然后flush在内存中的log消息到磁盘)影响了线程在gdb里面的顺序。于是我修改程序去掉了信号的处理的函数。等待再次crash的时候发现这个时候gdb中的第一线程的callstack中所显示的代码确实有问题,有个地方没有判断是否是NULL就开始操作了。

  上面导致crash的代码逻辑很容易修改,但是这个事情也告诉我。在多核的环境下,如果在信号的处理函数中还做了一些事情(我估计特别是这个事情需要再次进入内核)那么用gdb打开core文件得到的第一个线程不一定是真正导致程序crash的那个线程。现在的解决方案很简单,如果你觉得gdb打开的core文件的第一个线程怎么看都不太像是有问题的线程,那就看看其他线程吧。没准在其他的线程里面可以找到真正引起错误的元凶。

Categories: programming Tags: , ,