1

最近、segfault の問題が発生しました。delete メソッドを呼び出すときにヒットします。私はコードを詳細に調べ、ヌル ポインターの削除、複数の削除、または範囲外の可能性を排除しました (割り当てられたメモリは、後で書き込まれるコンテンツを保持するのに十分な大きさです)。この問題は、同じ場所で segfault が発生するたびに再現できます。

この問題の原因が何かわかりません。次のようなエラー コードから手がかりを得ることができるかどうか疑問に思います。

私はかなり長い間ネットを検索しましたが、stackoverflowから次の有用な情報のみを取得しました:-

「エラー コードは、ページ フォールトの単なるアーキテクチャ エラー コードであり、アーキテクチャ固有のようです。多くの場合、カーネル ソースの arch/*/mm/fault.c に文書化されています。Linux/arch/i386/mm/ の私のコピーfault.c には、error_code の次の定義があります。

bit 0 == 0 means no page found, 1 means protection fault
bit 1 == 0 means read, 1 means write
bit 2 == 0 means kernel, 1 means user-mode

"

これが私の質問です:- エラーコード 4 (私のプラットフォームは RHEL5 64 ビット、x86_64) の考えられる原因は何ですか? エラーコードから考えられる原因を特定する方法はありますか?

この種の問題を診断する方法についての他のアドバイスも大歓迎です!

4

1 に答える 1

1

あなたが提供するドキュメントを考えるとarch/i386/mm/fault.c、エラーコード 4 は「ページのユーザーモード読み取りが見つかりません」に対応します。コード 4 のバイナリ表現 = 100。ビット 2 が最上位 (左端) ビットです。

SIGSEGVこれは、 aに aを受け取る最も一般的な原因でdeleteある二重解放 (すでに解放されているポインターを解放しようとする) と一致します。ただし、ヒープの破損 (たとえば、他の何かを二重に解放したり、別の場所でバッファ オーバーフローや範囲外エラーが発生したりした場合) が原因である可能性があります。

valgrindメモリ割り当てルーチンのデバッグ バージョン (MALLOC_CHECK_バイナリを実行する前に環境内で 1 または 2 に設定) の下でコード (デバッグ シンボルでコンパイル) を実行するか、それを使用して実行してみてください。これらのエラーをキャッチして報告しようとする 2 つの異なるアプローチそれらが作られたらすぐにあなたにそれらを。

valgrindメモリ モデルが網羅されており、適切な量のチェックをオンにすると、ほぼ確実に問題の原因を突き止めることができます。

MALLOC_CHECK_glibc の内部にあり、他のほとんどのメモリ デバッグ インストルメンテーション ツールと同様に、valgrind特定のタイプの比較的一般的なエラーのみをキャッチし、場合によってはヒープの破損を検出できます。そこに似た他のツールMALLOC_CHECK_(Electric Fence など) はたくさんありますが、前者は既に C ライブラリに組み込まれており、他のツールはせいぜいライブラリ (主に含まれてオーバーライドするもの) が動的である必要がmallocありfreeます。を使用して C ライブラリの前にリンクされますLD_PRELOAD

ヌル ポインターでC++ を使用deleteすることは技術的には問題ではないことに注意してください。そのため、チェックリストから削除することができます (削除する前にコードを明示的にチェックするようにコードを変更することにより、おそらく既にお持ちだと思います)。

詳細:

「ページのユーザー モード読み取りが見つかりません」に対応するエラー コードは、メモリへのポインター (仮想アドレス空間のどこかを参照する 32/64 ビットの数値) が逆参照されたことを意味します (つまり、一部のコードがページを読み取ろうとしました)。ポインタが保持していた仮想メモリアドレスの値) しかし、カーネルページテーブルは、仮想アドレスが、プロセスにマップされていないか、そのポインタが有効だったためにプロセスからマップ解除された [メモリの] ページを参照していることを示しています. これが起こることを想像する明白な方法は別として、破損したヒープ (舞台裏であらゆる種類の簿記情報を含む) が原因で間接的に発生する可能性があります。たとえば、渡した値に対してポインター演算が行われる場合があります。deleteヒープ内部の以前に破損した別のポインターを使用すると、ポインターに無効な値が存在し、コードがそれを使用しようとするのを待つだけになります。

つまり、カーネル エラー コードは、一般的なデバッグ シナリオではあまり役に立ちません。

プログラムを実行しgdb、クラッシュの数行前にブレークポイントを設定して、削除されるポインターの値と残りの周囲の状態を観察したとします。

編集:

-g2どうやら を意味していたときの誤った参照を削除しMALLOC_CHECK_ました。さらなる診断の質問と説明を追加しました。

于 2012-12-02T06:23:31.850 に答える