2012-02-26 4 views
10

私は解決できない奇妙な問題があります。助けてください!C++プログラムのコアダンプのバックトレースにある無限のabort()

このプログラムは、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?). 
を示し

これはスレッド2-6がスレッド#1に作成されるために発生します。

gdbでプログラムを実行できないのは、組み込みシステム上で動作するためです。私はリモートgdbサーバーを使用することはできません。唯一のオプションは、あまり頻繁ではないコアダンプを調べることです。

これで私を前進させるものをお勧めしますか? (おそらく何か他のコードをコアダンプから抜き出すことができます。あるいは、何とかしてコードにフックを入れてabort()を呼び出すことができます。呼び出し)。

更新:Basile Starynkevitch Valgrindを使用するように提案されていますが、ARMv7専用に移植されています。私はARMv5であるARM926を持っているので、これは私にとってはうまくいかないでしょう。しかし、ARMv5用のvalgrindをコンパイルするいくつかの努力があります。Valgrind cross compilation for ARMv5telvalgrind on the ARM9

更新2:私のプログラムでElectric Fenceを動作させることができませんでした。プログラムはC++とpthreadを使用します。私がスレッドを開始して多かれ少なかれ複雑なことをしようとすると、2.1.13がEfenceのバージョンを任意の場所でクラッシュさせました(たとえば、STLベクトルに値を入れるなど)。私はWeb上でEfence用のパッチについて言及していましたが、試してみる時間がありませんでした。私はARMではなく、私のLinux PCでこれを試しました。そして、valgrindやDmallocのようなツールは、コードに何の問題も報告しません。したがって、バージョン2.1.13のefenceを使用しているすべての人は、pthreads(または多分pthread + C++ + STL、わからない)に問題を持つ準備ができています。

+4

(最近ARM、IIRCに移植されている) 'valgrind'を使う良い理由があるようです。 http://valgrind.org/ –

+0

ありがとうございました!それがARMに移植されたことを知らなかった –

+0

valgrindはARM v7のみに移植されています。私はARM926プロセッサを持っており、コンパイラはそれを構築することを拒否しています:( –

答えて

3

「無限」のアボートは、abort()がループを引き起こすか(例えば、abort->シグナルハンドラ - >アボート - > ...)、gdbがスタック上のフレームを正しく解釈できない。

いずれの場合でも、問題のあるスレッドのスタックを手動でチェックすることをお勧めします。アボートがループを引き起こす場合は、パターンを表示するか、少なくともリターンアドレスを頻繁に繰り返す必要があります。 (繰り返し)スタックの大部分を手動でスキップすることで、問題の根本を簡単に見つけることができます。

そうでなければ、繰り返しパターンがなく、うまくいけば、スタック上のどこかで機能していない関数の戻りアドレスが見つかるはずです。最悪の場合、そのようなアドレスはバッファオーバーフローなどで上書きされますが、おそらくそれでもあなたは幸運になり、上書きされたものを認識できます。

+0

ありがとう、@mweerdeen、私はそれを試みる! –

1

ここでの可能性の1つは、オンスレッドデータ構造を大幅に上書きし、スタック内のすべての必要なデータを破壊することによって、そのスレッド内の何かが非常に非常にひどくスタックを壊してしまったことです。それは死後のデバッグを非常に不愉快にする。

問題を再現できるのであれば、gdbの下でスレッドを実行し、スタックがヌークになった瞬間に何が起こっているのかを正確に監視することです。これは、正確にエラーが発生している場所を特定するために、何らかの慎重な検索が必要になることがあります。

あなたが問題を再現できない場合は、そのスレッドが死に至る前に実行されていた場所をヒントしているかどうかを確認するためにスレッドのローカルストレージ内のヒントを非常に注意深く探してください。

+0

残念ながら、postmortemコアダンプだけが私に利用可能です - ( –

関連する問題