4

最近、製品の欠陥を修正しました。その症状は、ダングリングポインターへのアクセスによって引き起こされたアクセス違反でした。

良い習慣として、バグが再発しないことを確認するために単体テストを追加しました。単体テストを作成するときは、常に欠陥修正を取り消して、単体テストが失敗することを確認します。そうしないと、単体テストが適切に機能していないことがわかります。

欠陥修正を取り消した後、ユニットテストがまだ合格していることを発見しました(良くありません)。デバッガーを単体テストに接続して合格した理由を確認すると、テストが失敗し(つまり、例外がスローされ)、コールスタックが壊れて、修正した元の欠陥のスタックと一致することがわかりました。

Visual Studio 2005の[例外の中断]設定を変更しませんでした。これは実際に重大なWin32例外であり、テストハーネスが終了します(つまり、正常な例外ハンドラーがありません)。

例外のテキストは次のとおりです。

Unhandled exception at 0x0040fc59 in _testcase.exe: 0xC0000005:
Access violation reading location 0xcdcdcdcd.

注:場所は常にではありません0xcdcdcdcd割り当てられていますが、書き込まれていないWin32ヒープメモリ)。ある場合もあれ0x00000000ば、別のアドレスである場合もあります。

これは、デバッガーを介して問題を観察すると問題が解消される、従来のHeisenbugの逆のように見えます。私の場合、デバッガーでそれを観察すると問題が発生します!

私の最初の考えは、これはデバッガーのタイミングの違いによって明らかになった競合状態であるということでした。ただし、コードにトレースを追加してデバッガーとは別に実行した場合、出力するデータは、デバッガーで実行する場合と同様の方法でアプリケーションを中止する必要があることを示しています。そうではありません!

これを引き起こしている可能性があるものについての提案はありますか?


更新: 私はこの問題の原因を絞り込んでいます。詳細については、この質問を参照してください。私がそれを見つけたら、答えでこの質問を更新します。

4

4 に答える 4

3

通常、VC ++デバッガーは、ヒープに割り当てられたメモリへのポインターを削除すると、そのメモリを既知の値でいっぱいにします。Visual Studioを使用してからかなり時間が経ちましたが、0xcdcdcdcdがそのような値である可能性があることは私には合理的であるように思われます。デバッガーで実行しているときにアプリケーションが適切にクラッシュしている可能性が最も高いようです。リリースモードで実行している場合、ランタイムは割り当て解除されたメモリを上書きする時間を無駄にしないため、「幸運」になり、そのメモリに格納されているデータは引き続き有効です。

ビルド設定を変更して、解放モードで割り当て解除されたメモリを既知の値で埋めるオプションをオンにすることができます(完了したら、再度オフにすることを忘れないでください)。これを行うと、アプリケーションがリリースモードでクラッシュすると思います。

値が常に0xcdcdcdcdであるとは限らないことを理解しています。これは、私が間違っているか、ダングリングポインタへのパスが複数あることを意味している可能性があります。

于 2010-11-25T03:45:14.630 に答える
2

私はこの数年前に逆に遭遇しました。この問題は、デバッガーが接続されていない場合にのみ発生していました。

コードが以前のメソッドアクティベーションのスタックフレームを破損しており、デバッガーを使用すると中間スタックフレームが導入されたことが判明しました。

あなたはおそらく同様の状況にあります。

于 2010-11-25T01:30:24.220 に答える
0

これが役立つかどうかはわかりませんが、プログラムをVisual Studioデバッガーで実行した場合、またはプログラムを外部で実行してからデバッガーを接続した場合に、異なる形で現れるバグに遭遇したことがあります。

于 2010-11-25T01:21:07.943 に答える
0

この問題の原因を特定しました。詳細については、この質問を参照してください。

デバッガーでテストハーネスを実行すると、デバッグ環境で消費されるメモリは、同じオブジェクトの後続の割り当て/割り当て解除が常にメモリの異なる部分に割り当てられることを意味しました。これは、テストハーネスがダングリングポインタにアクセスしようとすると、テストがクラッシュしたことを意味します(技術的にはこれは未定義の動作ですが、これはテストコードであり、必要な処理を実行しているようです)。

コマンドラインからテストハーネスを実行すると、同じオブジェクトの後続の割り当て/割り当て解除は、常に同じメモリブロックを再利用しました。この偶然の振る舞いは、テストケースで実際にダングリングポインターであるものにアクセスしたときに、ダングリングポインターがまだ有効なオブジェクトを指していることを意味しました。だから私はクラッシュを見なかった。

于 2010-11-25T06:13:43.053 に答える