2

一日中実行されている大量のコードがあります。週に一度、ポインタを解放しようとするとクラッシュします:

delete [] p

バック トレース (gdb を使用):

0x00007f4f709f2885 in raise () from /lib64/libc.so.6
0x00007f4f709f4065 in abort () from /lib64/libc.so.6
0x00007f4f70a2f7a7 in __libc_message () from /lib64/libc.so.6
0x00007f4f70a350c6 in malloc_printerr () from /lib64/libc.so.6

削除が失敗する原因を突き止めたい:重複削除またはその他の何か。どうやってやるの?

4

2 に答える 2

2

まず、バックトレースに call が含まれていることに注意してくださいmalloc_printerr。この関数は理由を標準エラーに書き込みますので、キャプチャすることを忘れないでください!

新規/削除タイプの不一致、二重削除、または無効なポインターのいずれであっても、実際のバグは、実際にそれを検出する削除のずっと前に発生します。そのため、gdb はあまり役に立ちません。関連するポインターに発生したことをすべてログに記録し、問題が発生したときに掘り下げる必要があります。

  • 完全に無効なポインターである場合は、初期化されていないメモリまたはバッファ オーバーランで上書きされます。すべてのオブジェクトに、関連する可能性のあるポインターをゼロにする正しいコンストラクターがあることを確認してください。どちらの問題もvalgrindでキャッチできます。バッファ オーバーランも、 DUMA ライブラリまたはマッドフラップ(gcc に同梱) を使用して、より少ないオーバーヘッド (ただし精度は低くなります) でキャッチできます。
  • 二重削除の場合は、デストラクタの場合を除いて、関連するポインタを削除した後にゼロにすることを確認してください (デストラクタで削除する場合は、コンストラクタで初期化したことを確認してください)。関連するポインターのすべての操作のログ メッセージを追加し、クラッシュしたときに、ポインターが復活したように見えるログをトレース バックします。無効なポインターに対してもそれを試みることができます。
  • 不一致の場合は、常に withを割り当てたときに[]削除し、それ以外の場合は決して削除しないようにし、常に完全な型を削除していることを確認してください (C++ は不完全な型の削除を受け入れ、未定義の動作です)。[][]
  • 上記のいずれも、関連するポインタを保持するオブジェクトのデストラクタを適切に呼び出さないことによる二次的な影響である可能性があります。デストラクタの呼び出しに失敗すると、不適切な型のポインタを削除したり、不完全な型へのポインタを削除したり[]、新規と削除で不一致になったりする可能性があります。レビューに加えて、関連する可能性のあるコンストラクタとデストラクタにログを追加し、それらが適切に一致していることをログで確認します。

実際にエントリを照合できるように、ポインタ値を常にログに記録することを忘れないでください。また、ログを分析するためのスクリプトを作成する必要がある場合もあります (一致しないエントリを見つけます)。十分なスペースを確保してください。この方法で数ギガバイトのログを生成するのはかなり簡単です。

疑わしいいくつかの操作を絞り込んだら、バックトレースをログに書き込む必要がある場合があります。backtrace(3)ライブラリ関数またはlibunwindを見てください。

于 2013-01-16T09:14:16.507 に答える
1

適切な単体テストを作成し、valgrind を使用してそれらを実行し、バグを見つけられることを願っています。

それ以外の場合は、コードを見てバグを検索できます (たとえば、「Good Clues, Easy Bugs」の記事ではデバッグ手法について説明しています)。

于 2013-01-16T08:47:10.447 に答える