ハイゼンバグ:一部のコンピューターで WinApi プログラムがクラッシュする
質問
助けてください!本当に途方に暮れています。私のプログラムは小さな個人的なメモマネージャーです (グーグルで「cintanotes」で検索してください)。一部のコンピュータ (もちろん私はどれも所有していません) では、起動直後に未処理の例外が発生してクラッシュします。これらのコンピューターについては、AMD CPU が搭載されている傾向があることを除けば、特別なことは何も言えません。
環境:Windows XP、Visual C++ 2005/2008、生の WinApi。
この「ハイゼンバグ」について確かなことは次のとおりです。
1) クラッシュはリリース バージョンでのみ発生します。
2) GDI 関連のものをすべて削除すると、クラッシュはすぐに消えます。
3) BoundChecker には何の不満もありません。
4) ログを書くと、ローカル int 変数の宣言でクラッシュが発生していることがわかります。どうしてそんなことがあり得るでしょうか?メモリ破損?
アイデアがあれば大歓迎です。
アップデート:「故障した」PC 上でアプリをデバッグすることに成功しました。結果:
「CintaNotes.exe の 0x0044a26a で未処理の例外:0xC000001D:違法な指導です。」
そしてコードが中断される
0044A26A cvtsi2sd xmm1,dword ptr [esp+14h]
したがって、問題は「コード生成/拡張命令セットを有効にする」コンパイラ オプションにあるようです。これは「/arch:SSE2」に設定されており、SSE2 をサポートしていないマシンではクラッシュしていました。このオプションを「未設定」に設定したところ、バグは解消されました。ふう!
みなさん、助けてくれて本当にありがとうございました!!
解決
つまり、設定がDEBUG設定の場合はクラッシュしないのでしょうか?RELEASE 構成とは異なる点が数多くあります。1.)グローバルの初期化2.)生成された実際のマシンコードなど..
したがって、最初のステップは、DEBUG モードと比較して RELEASE モードでの各パラメーターの正確な設定を確認することです。
-広告
他のヒント
4) ログを書き込むと、ローカルの int 変数の宣言でクラッシュが発生したことがわかります。どうしてそうなるでしょうか?メモリ破損?
実行可能ファイル/アセンブリの基礎となるコードは何ですか?int の宣言はまったくコードではないため、クラッシュすることはありません。何らかの方法でintを初期化しますか?
クラッシュが発生したコードを確認するには、いわゆる事後分析を実行する必要があります。
Windows エラー報告
クラッシュを分析したい場合は、クラッシュ ダンプを取得する必要があります。このための 1 つのオプションは、Windows エラー報告に登録することです。これには、ある程度のお金 (デジタル コード署名 ID が必要です) とフォームへの入力が必要です。詳細については、こちらをご覧ください https://winqual.microsoft.com/ .
WER 向けのクラッシュ ダンプを顧客から直接取得します。
もう 1 つのオプションは、クラッシュが発生しているユーザーに連絡して、そのユーザーから WER 用のクラッシュ ダンプを直接取得することです。ユーザーは、クラッシュを Microsoft に送信する前に [技術的な詳細] をクリックすると、これを行うことができます。クラッシュ ダンプ ファイルの場所はそこで確認できます。
独自のミニダンプ
もう 1 つのオプションは、独自の例外ハンドラーを登録し、例外を処理して、必要な場所にミニダンプを書き込むことです。詳細な説明は次の場所にあります。 コード プロジェクトのミニダンプと Visual Studio .NET を使用したアプリケーションの事後デバッグに関する記事.
1) クラッシュはリリース バージョンでのみ発生します。
これは通常、保証されていないものの、デバッグ ビルドではたまたま当てはまる動作に依存していることを示しています。たとえば、変数の初期化を忘れた場合や、範囲外の配列にアクセスした場合などです。すべてのコンパイラ チェック (/RTCsuc) がオンになっていることを確認してください。また、関数パラメーターの評価順序に依存するかどうか (保証されていません) なども確認してください。
2) GDI 関連のものをすべて削除すると、クラッシュはすぐに消えます。
おそらくそれは、GDI 関連で何か間違ったことをしているというヒントですか?たとえば、HANDLE を解放した後に使用していますか?
ダウンロード Windows用のデバッグツール パッケージ。シンボル パスを正しく設定し、WinDbg でアプリケーションを実行します。ある時点で、アクセス違反が発生して壊れます。次に、「!analyze -v」コマンドを実行する必要があります。これは非常に賢明で、何が問題なのかのヒントが得られるはずです。
ハイゼンバグ/リリースのみのバグのほとんどは、初期化されていないメモリ/古いポインタ/過去のバッファの終わりからの読み取りに依存する制御フロー、または競合状態、またはその両方が原因です。
アロケータをオーバーライドして、割り当て時にメモリをゼロにするようにしてください。問題は解決しますか (またはより再現可能になりますか?)
ログを書き出すと、ローカルの int 変数の宣言でクラッシュが発生していることがわかります。どうしてそんなことがあり得るでしょうか?メモリ破損?
スタックオーバーフロー!;)
4) ログを書き込むと、ローカルの int 変数の宣言でクラッシュが発生したことがわかります。どうしてそうなるのでしょうか?メモリ破損
多数の「奇妙なクラッシュ」の原因は、壊れたオブジェクトの参照解除であることがわかりました。 this
前記オブジェクトのメンバー関数内。
クラッシュは何を言っていますか?アクセス違反 ?例外 ?それはこれを解決するためのさらなる手がかりになります
PageHeap.exe を使用して、以前のメモリ破損がないことを確認します。
スタック オーバーフローがないことを確認します (CBig array[1000000])
初期化されていないメモリがないことを確認してください。
さらに、プロセスのデバッグ シンボル (デバッグ バージョンの作成とは異なります) を生成すると、デバッガー内でもリリース バージョンを実行できます。手順を進めて、デバッガのトレース ウィンドウに警告が表示されるかどうかを確認します。
"4) ログを書くと、ローカル int 変数の宣言でクラッシュが発生していることがわかります。どうしてそんなことがあり得るでしょうか?メモリ破損?」
これは、ハードウェアに実際に欠陥があるか、過度に負荷がかかりすぎていることを示す兆候である可能性があります。コンピューターをオーバークロックしたかどうかを確認します。
この種の現象が発生した場合は、BoundsChecker に対してさまざまなクラスのエラーをチェックするため、gimpels PC-Lint (静的コード分析) を通じてコードを実行してみます。Boundschecker を使用している場合は、メモリ ポイズニング オプションをオンにします。
AMD CPUについて言及していますね。クラッシュするマシンに同様のグラフィックス カード、ドライバーのバージョン、構成が存在するかどうかを調査しましたか?これらのマシンでは常にクラッシュしますか、それとも時々だけですか?おそらく、これらのマシンでシステム情報ツールを実行して、それらの共通点を確認してください。
スタックが破損しているように思えます。それらを追跡するための私のお気に入りのツールは、 IDAプロ. 。もちろん、ユーザーのマシンにアクセスする権限はありません。
一部のメモリ チェッカーは、スタック破損を検出するのが困難です (実際に破損している場合)。これらを取得する最も確実な方法は、実行時分析だと思います。
これは、例外が処理された場合でも、例外パスの破損が原因である可能性があります。「初回例外のキャッチ」をオンにしてデバッグしていますか?できる限りそうすべきです。多くの場合、しばらくするとイライラします。
それらのユーザーにアプリケーションのチェック済みバージョンを送信できますか?チェックアウト ミニダンプ その例外を処理し、ダンプを書き出します。次に、使用します WinDbg あなたの側でデバッグします。
もう 1 つの方法は、非常に詳細なログを書き込むことです。「すべてのアクションをログに記録する」オプションを作成し、それをオンにしてあなたにも送信するようにユーザーに依頼します。メモリをログにダンプアウトします。MSDN の「_CrtDbgReport()」を確認してください。
幸運を!
編集:
コメントへの返信:ローカル変数宣言のエラーは私にとって驚くべきことではありません。これはよく見ました。通常、スタックの破損が原因です。
たとえば、スタック上の一部の変数がその境界を超えて実行されている可能性があります。その後、すべての地獄が解き放たれます。その後、スタック変数の宣言によりランダムなメモリ エラーが発生したり、仮想テーブルが破損したりすることがあります。
それらを長時間見ていると、IDA Pro に行かなければならなくなりました。 詳細なランタイム逆アセンブリデバッグ これらを確実に取得できるのは、私が知っている唯一のことです。
多くの開発者は、この種の分析に WinDbg を使用します。だからこそ、私も Minidump を提案しました。
Rational (IBM) PurifyPlus をお試しください。BoundsChecker では検出できない多くのエラーを検出します。