6

バックグラウンド

  • Poof-Crash [ 1 ]のあるアプリケーションがあります。吹き飛ばされたスタックが原因であると確信しています。
  • アプリケーションはマルチスレッドです。
  • " " でコンパイルしていEnable C++ Exceptions: Yes With SEH Exceptions (/EHa)ます。
  • SE トランスレーター関数を作成し、それを呼び出し_set_se_translator()ました。
  • set_terminate()と setupとの関数を書きましset_unexpected()た。
  • スタック オーバーフローを取得するには、負荷の高い状態でリリース モードで数日間実行する必要があります。アプリケーションは、問題を確認するために必要なランタイムを達成するのに十分な速度で実行できないため、デバッガーの下で実行することはできません。
  • 関数の 1 つの実行時に無限再帰を追加することで問題をシミュレートし、EXCEPTION_STACK_OVERFLOW例外のキャッチをテストできます。
  • クラッシュ ダンプ プログラムとして WinDBG をセットアップしましたが、他のすべてのクラッシュの問題に関する適切な情報が得られますが、この問題に関する情報は得られません。クラッシュ ダンプには、'Sleep()'ing である 1 つのスレッドのみが含まれます。他のすべてのスレッドは終了しました。

質問

EXCEPTION_STACK_OVERFLOW私が試したことのどれも、例外を拾うことにはなりませんでした。

リリースモードでの実行時にこの例外が発生する可能性を保証する方法を知っている人はいますか?

定義

  1. Poof-Crash : アプリケーションがクラッシュし、"poof" して跡形もなく消えます。

(このサイトの名前を考えると、この質問がまだここにないことに驚きました!)

ノート

  1. スタックサイズを調整して問題をより早く強制し、デバッガーでキャッチできるようにすることについての簡単な回答が投稿されました。それは賢明な考えですが、残念ながら、それが役立つとは思えません。この問題は、無限再帰につながるコーナー ケースが原因である可能性があります。スタックを短くしても、問題がすぐに明らかになることはなく、有効に深いコードで無関係なクラッシュが発生する可能性があります。良いアイデアですが、削除してしまったにもかかわらず、投稿していただきありがとうございます。
4

5 に答える 5

5

通常、Windows XP より前のバージョンでは、スタック オーバーフローをトラップすることはできません (またはより困難になります)。xp の出現により、スタックベース (構造化例外) ハンドラーの前にスタック オーバーフローの可能性を得る ベクトル化された例外ハンドラーを設定できます (これがまさにその理由です - 構造化例外ハンドラーはスタックベースです)。

しかし、そのような例外をトラップできたとしても、実際にできることはあまりありません。

のブログで、cbrumme (申し訳ありませんが、彼/彼女の本名はありません) は、バックアウトに使用される可能性があるガード ページ (スタック オーバーフローを生成するページ) に隣接するスタック ページについて説明しています。スタック ページを 1 つだけ使用するようにバックアウト コードを絞ることができれば、ロジックが許す限り解放できます。そうしないと、スタック オーバーフローが発生した時点で、アプリケーションはほとんど機能しなくなります。他の唯一の合理的な方法は、それをトラップした後、後でデバッグするためにダンプ ファイルを作成することです。

それが役に立てば幸い。

于 2009-01-13T12:57:55.553 に答える
4

これをスタック オーバーフローと診断するにあたって、あなたが正しい方向に進んでいるとは思えません。

しかし、いずれにせよ、あなたがうんざりしているという事実!、さらに WinDbg に表示されているもの

クラッシュ ダンプには、'Sleep()'ing である 1 つのスレッドのみが含まれます。他のすべてのスレッドは終了しました。

誰かが C RTL の exit() 関数を呼び出したか、Windows API の TerminateProcess() を直接呼び出した可能性があることを示唆しています。それは、割り込みハンドラーと関係があるかどうかに関係している可能性があります。おそらく、例外処理ロジックの何かに再入チェックがあり、再入された場合は任意に exit() を決定します。

私の提案は、実行可能ファイルにパッチを適用して、出口 () のエントリ ポイントに INT 3 デバッグを配置することです。静的にリンクされている場合、または動的にリンクされている場合は、インポートにパッチを適用し、kernel32::TerminateProcess のインポートにもパッチを適用します。代わりに DebugBreak() をスローします。

もちろん、exit() および/または TerminateProcess() は通常のシャットダウンでも呼び出される可能性があるため、誤報を除外する必要がありますが、終了しようとしている場合のコール スタックを取得できれば、証明してください、あなたは必要なものを持っているはずです。

EDIT ADD: 単に独自のバージョンの exit() を作成し、CRTL バージョンの代わりにリンクするだけでうまくいく場合があります。

于 2009-01-14T00:03:34.617 に答える
1

スタック ポインターで明示的な境界チェックを行い、手動で例外をスローするように聞こえる以前の職場のコードを覚えています。

C++に触れてからしばらく経ちましたが、触れたときでさえ、自分が何をしているのかわからなかったので、前述のアドバイスの移植性/信頼性について実装者に注意してください.

于 2009-01-12T20:27:10.203 に答える
0

最適化を無効にすることなく、デバッグ シンボルを生成できます。実際、とにかくそれを行う必要があります。デバッグが難しくなるだけです。

また、のドキュメントに_set_se_translatorは、各スレッドに独自の SE トランスレータがあると書かれています。スレッドごとに1つ設定していますか?

set_unexpected少なくとも VS 2005 のドキュメントによると、おそらくノーオペレーションです。また、各スレッドにも独自のterminateハンドラーがあるため、それもスレッドごとにインストールする必要があります。

また、SE 翻訳を使用しないことを強くお勧めします。無視してはならないハードウェア例外 (つまり、実際にエラーをログに記録して終了する必要があります)を受け取り、それらを無視できるもの (C++ 例外) に変換します。この種のエラーをキャッチする場合は、__try/__exceptハンドラーを使用します。

于 2009-01-12T20:34:22.480 に答える