无限的abort()在c ++程序核心转储的背后

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

该程序是在ARM Linux机器上运行的multithreadingc ++应用程序。 最近我开始testing它的长时间运行,有时会在1-2天之后崩溃,如下所示:

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

当我打开核心转储我看到主线程似乎有一个损坏的堆栈:我所看到的是无限的中止()调用。

 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 () 

它继续下去。 我试图通过向上移动堆栈来实现它的底部: frame 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?). 

它发生的原因是线程2-6是在线程#1中创build的。

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

你能提出一些可以推动我前进的东西吗? (也许别的东西我可以从核心转储中提取,或者可能以某种方式使代码中的某个钩子捕获abort()调用)。

更新: 巴西尔Starynkevitchbuild议使用Valgrind,但事实certificate,它只适用于ARMv7。 我有ARM 926是ARMv5,所以这不适合我。 虽然有一些努力来编译valgrind for ARMv5: Valgrind交叉编译为ARMv5tel , valgrind在ARM9

更新2:无法使电气栅栏与我的程序工作。 该程序使用C ++和pthreads。 在我开始一个线程之后, 2.1.13的Efence版本在任意位置崩溃,并尝试做一些或多或less复杂的事情(例如,为STL向量赋值)。 我看到有人在网上提到Efence的一些补丁,但没有时间去尝试。 我在我的Linux PC上试过,而不是在ARM上,其他工具如valgrind或Dmalloc不会报告任何代码问题。 因此,每个人使用的版本2.1.13的efence准备有问题与pthreads(或者pthread + C ++ + STL,不知道)。

我对“无限”放弃的猜测是,abort()会导致一个循环(例如,abort – > signal handler – > abort – > …),或者gdb无法正确解释栈上的帧。

在这两种情况下,我会建议手动检查有问题的线程的堆栈。 如果中止导致一个循环,你应该看到一个模式或至少是中止重复的地址。 也许你可以通过手动跳过(重复)堆栈的大部分来更容易地找到问题的根源。

否则,你会发现没有重复的模式,并希望堆栈上的某个失败函数的返回地址。 在最坏的情况下,由于缓冲区溢出等原因,这些地址被覆盖,但也许你仍然可以幸运地认出它被覆盖了什么。

其中一种可能性是该线程中的某些东西通过大量覆盖堆栈上的数据结构而非常非常糟糕地破坏了堆栈,从而破坏了堆栈中所有需要的数据。 这使得事后调试非常不愉快。

如果你可以随意复制这个问题,那么正确的做法就是在gdb下运行线程,并且在堆栈被掩盖的时刻准确地看到发生了什么。 这可能反过来需要一些仔细的搜索来确定错误发生的地方。

如果你不能随意重现这个问题,那么我可以建议的最好的方法是非常仔细地寻找线程本地存储中的线索,看看它是否暗示死亡命中之前线程正在执行的地方。