我有一个无法解决的奇怪问题。请帮忙!

该程序是一个在ARM Linux计算机上运行的多线程c++应用程序。最近,我开始对其进行长期测试,有时它会在1-2天后崩溃,如下所示:

*** glibc detected ** /root/client/my_program: free(): invalid pointer: 0x002a9408 ***

当我打开核心转储时,我看到它的主线程似乎有一个损坏的堆栈:我所看到的只是无限的abort()调用。
GNU gdb (GDB) 7.3
...
This GDB was configured as "--host=i686 --target=arm-linux".
[New LWP 706]
[New LWP 700]
[New LWP 702]
[New LWP 703]
[New LWP 704]
[New LWP 705]
Core was generated by `/root/client/my_program'.
Program terminated with signal 6, Aborted.
#0  0x001c44d4 in raise ()
(gdb) bt
#0  0x001c44d4 in raise ()
#1  0x001c47e0 in abort ()
#2  0x001c47e0 in abort ()
#3  0x001c47e0 in abort ()
#4  0x001c47e0 in abort ()
#5  0x001c47e0 in abort ()
#6  0x001c47e0 in abort ()
#7  0x001c47e0 in abort ()
#8  0x001c47e0 in abort ()
#9  0x001c47e0 in abort ()
#10 0x001c47e0 in abort ()
#11 0x001c47e0 in abort ()

而且它还在继续。我试图通过向上移动堆栈来达到最低点:帧3000甚至更多,但是最终核心转储用完了帧,我仍然不明白为什么会发生这种情况。

当我检查其他线程时,那里的一切似乎都很正常。
(gdb) info threads
  Id   Target Id         Frame
  6    LWP 705           0x00132f04 in nanosleep ()
  5    LWP 704           0x001e7a70 in select ()
  4    LWP 703           0x00132f04 in nanosleep ()
  3    LWP 702           0x00132318 in sem_wait ()
  2    LWP 700           0x00132f04 in nanosleep ()
* 1    LWP 706           0x001c44d4 in raise ()
(gdb) thread 5
[Switching to thread 5 (LWP 704)]
#0  0x001e7a70 in select ()
(gdb) bt
#0  0x001e7a70 in select ()
#1  0x00057ad4 in CSerialPort::read (this=0xbea7d98c, string_buffer=..., delimiter=..., timeout_ms=1000) at CSerialPort.cpp:202
#2  0x00070de4 in CScanner::readResponse (this=0xbea7d4cc, resp_recv=..., timeout=1000, delim=...) at PidScanner.cpp:657
#3  0x00071198 in CScanner::sendExpect (this=0xbea7d4cc, cmd=..., exp_str=..., rcv_str=..., timeout=1000) at PidScanner.cpp:604
#4  0x00071d48 in CScanner::pollPid (this=0xbea7d4cc, mode=1, pid=12, pid_str=...) at PidScanner.cpp:525
#5  0x00072ce0 in CScanner::poll1 (this=0xbea7d4cc)
#6  0x00074c78 in CScanner::Poll (this=0xbea7d4cc)
#7  0x00089edc in CThread5::Thread5Poll (this=0xbea7d360)
#8  0x0008c140 in CThread5::run (this=0xbea7d360)
#9  0x00088698 in CThread::threadFunc (p=0xbea7d360)
#10 0x0012e6a0 in start_thread ()
#11 0x001e90e8 in clone ()
#12 0x001e90e8 in clone ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

(类和函数的名称有些奇怪,因为我将它们更改为-:)
因此,线程1是堆栈损坏的地方,其他(2-6)的回溯显示
Backtrace stopped: previous frame identical to this frame (corrupt stack?).

这是因为在线程#1中创建了线程2-6。

问题是我无法在gdb中运行该程序,因为它在嵌入式系统上运行。我不能使用远程gdb服务器。唯一的选择是检查不经常发生的核心转储。

您能否提出一些可以使我前进的建议? (也许我可以从核心转储中提取其他内容,或者以某种方式在代码中建立一些钩子(Hook)来捕获abort()调用)。

更新:Basile Starynkevitch建议使用Valgrind,但事实证明它仅用于ARMv7。我有ARM 926,即ARMv5,所以这对我不起作用。尽管有一些努力为ARMv5编译valgrind:Valgrind cross compilation for ARMv5telvalgrind on the ARM9

更新2:无法使电子围栏与我的程序一起使用。该程序使用C++和pthreads。我启动线程并尝试执行或多或少复杂的操作(例如,将值放入STL vector 中)后,得到的Efence版本2.1.13在任意位置崩溃。我在网上看到有人提到一些有关Efence的补丁,但没有时间去尝试。我在Linux PC上而不是在ARM上尝试过此操作,并且其他工具(如valgrind或Dmalloc)不会报告代码有任何问题。因此,使用efence版本2.1.13的每个人都准备对pthreads有问题(或者可能是pthread + C++ + STL,不知道)。

最佳答案

我对“无限”中止的猜测是,abort()会导致循环(例如中止->信号处理程序->中止-> ...),或者gdb无法正确解释堆栈中的帧。

无论哪种情况,我都建议手动 check out 有问题的线程的堆栈。如果中止导致循环,您应该会看到一个模式,或者至少是中止的返回地址如此频繁地重复。也许您可以通过手动跳过(重复)堆栈的大部分来更容易地找到问题的根源。

否则,您应该发现没有重复模式,并且希望失败函数的返回地址在堆栈中的某处。在最坏的情况下,此类地址会由于缓冲区溢出等原因而被覆盖,但是也许您仍然可以幸运地认识到它被覆盖了什么。

10-08 03:52
查看更多