問題タブ [structured-exception]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - C++ 例外処理と SEH の混合 (Windows)
システムによって割り当てられたターゲットメモリgetaddrinfo()
を取得するために呼び出す関数があります。多くの人が知っているように、getaddrinfo() によって割り当てられたメモリを解放するsockaddr*
には、 を呼び出す必要があります。freeaddrinfo()
さて、私の関数には、いくつかの関数が失敗したために例外をスローする可能性のある場所がいくつかあります。私の最初の解決策は、freeaddrinfo()
すべての if ブロックに を組み込むことでした。しかし、関数が戻る前にとにかくそれを呼び出さなければならなかったので、それは私には見苦しく見えました。
しかし、私が遭遇した問題は、スローステートメントを __try ブロックにコーディングすることが許可されていないことです。
次に、msdn を読み、throw ステートメントを __try ブロック内から呼び出されるヘルパー関数にスワップしようとしました...そしてほら、コンパイラはもうそれをうめきませんでした...
何故ですか?そして、これは安全ですか?これは私には意味がありません:/
コード:
編集:
以下を試してみましたが、整数をスローしても機能しますが、クラスを例外として使用すると機能しません:
なんで?:/
c++ - 構造化例外ハンドラー (SEH) がヒープの破損を検出しない
サードパーティのライブラリを使用して 1 つの単純なタスク (ラスタライズ) を実行する小さなユーティリティ (VC 2010、clr なし) を作成しています。後のユーティリティは、より大きなアプリケーションで使用されます。サード パーティ製ライブラリのヒープ破損が原因で、ユーティリティがクラッシュすることがあります。それは問題ありませんが、Windows (Vista/2008) では、「プログラムが動作を停止しました... プログラムを閉じる/デバッグする」というよく知られたダイアログが表示されます。私の場合(サーバー側)には適切ではありません。ユーティリティは、目に見える影響を与えることなく、静かにクラッシュ/終了する必要があります。
そのために、未処理の例外 (SetUnhandledExceptionFilter) 用に SEH をインストールしました。ハンドラーは、AV ( *(PDWORD)0 = 0 ) のような例外に対して完全に呼び出されますが、何らかの理由で、ヒープ破損の場合には呼び出されません。アンロード中に、サード パーティ製ライブラリ dll の 1 つの dllmain で破損が発生します。
いくつか質問があります。ハンドラーが呼び出されない理由を誰か説明できますか? そのダイアログを防ぐ別の方法はありますか?
windows - 64 ビット Windows がユーザー カーネル ユーザー例外をアンワインドできないのはなぜですか?
スタックがカーネル境界を超えると、例外中に 64 ビット Windows がスタックをアンワインドできないのはなぜですか? 32 ビット Windows ではできるのに。
この質問全体のコンテキストは次のとおりです。
OnLoad 例外が消えるケース – x64 でのユーザーモード コールバック例外
バックグラウンド
32 ビット Windows で、カーネル モードコードからコールバックされたユーザー モードコードで例外をスローすると、ユーザーモードコードから呼び出されます。
Windows の構造化例外処理 (SEH) はスタックを巻き戻し、カーネル モードを介して巻き戻し、ユーザー コードに戻ることができます。ここで例外を処理でき、有効なスタック トレースが表示されます。
ただし、64 ビット Windows にはありません
Windows の 64 ビット エディションでは、これを実行できません。
複雑な理由により、64 ビット オペレーティング システム(amd64 および IA64) で例外を伝播することはできません。これは、Server 2003 の最初の 64 ビット リリース以来ずっと当てはまりました。x86 では、これは当てはまりません。例外はカーネル境界を介して伝搬され、フレームを逆戻りさせます。
この場合、信頼できるスタック トレースをさかのぼる方法がないため、無意味な例外を表示するか、完全に非表示にするかを決定する必要がありました。
当時のカーネル アーキテクトは、保守的な AppCompat フレンドリーなアプローチを取ることを決定しました。つまり、例外を隠し、最善を尽くします。
この記事では、すべての 64 ビット Windows オペレーティング システムがどのように動作したかについて説明しています。
- Windows XP 64 ビット
- Windows Server 2003 64 ビット
- Windows Vista 64 ビット
- Windows Server 2008 64 ビット
しかし、Windows 7 (および Windows Server 2008) 以降、アーキテクトは考えを変えました。64 ビット アプリケーション (32 ビット アプリケーションではない) の場合のみ、(デフォルトで)これらのユーザー カーネル ユーザー例外の抑制を停止します。したがって、デフォルトでは、次のようになります。
- Windows 7 64 ビット
- Windows Server 2008
すべての 64 ビット アプリケーションで、これまで見られなかったこれらの例外が表示されます。
Windows 7 では、ネイティブ x64アプリケーションがこのようにクラッシュすると、Program Compatibility Assistantに通知されます。アプリケーションにWindows 7 マニフェストがない場合、PCA がアプリケーション互換性シムを適用したことを示すダイアログが表示されます。これは何を意味するのでしょうか?これは、次にアプリケーションを実行したときに、Windows が Server 2003 の動作をエミュレートし、例外が消えることを意味します。Server 2008 R2 には PCA が存在しないため、このアドバイスは適用されないことに注意してください。
だから質問
問題は、 32 ビット版の Windows ではできるのに、なぜ64 ビット版の Windows ではカーネル移行によってスタックを元に戻すことができないのかということです。
唯一のヒントは次のとおりです。
複雑な理由により、64 ビット オペレーティング システム(amd64 および IA64) で例外を伝播することはできません。
ヒントは複雑です。
私はオペレーティング システムの開発者ではないので、説明が理解できないかもしれませんが、その理由を知りたいのです。
更新: 32 ビット アプリの抑制を停止するホットフィックス
Microsoft は、32 ビット アプリケーションでも例外が抑制されないようにする修正プログラムをリリースしました。
KB976038: 64 ビット バージョンの Windows で実行されるアプリケーションからスローされる例外は無視されます
- コールバック ルーチンでスローされる例外は、ユーザー モードで実行されます。
このシナリオでは、この例外によってアプリケーションがクラッシュすることはありません。代わりに、アプリケーションは一貫性のない状態に入ります。その後、アプリケーションは別の例外をスローしてクラッシュします。
ユーザー モード コールバック関数は通常、カーネル モード コンポーネントによって呼び出されるアプリケーション定義の関数です。ユーザー モード コールバック関数の例は、Windows プロシージャとフック プロシージャです。これらの関数は、Windows メッセージを処理するため、または Windows フック イベントを処理するために、Windows によって呼び出されます。
ホットフィックスを使用すると、Windows がグローバルに例外を食べるのを止めることができます。
またはアプリケーションごと:
この動作は、XP および Server 2003 の KB973460 にも記載されています。
ヒント
xperf を使用して 64 ビット Windows でスタック トレースをキャプチャすることを調査しているときに、別のヒントを見つけました。
Xperf でのスタック ウォーキング
ページングエグゼクティブを無効にする
64 ビット Windows でトレースを機能させるには、DisablePagingExecutiveレジストリ キーを設定する必要があります。これは、カーネル モード ドライバーとシステム コードをディスクにページングしないようにオペレーティング システムに指示します。これは、xperf を使用して 64 ビット コール スタックを取得するための前提条件です。 xperfスタック ウォーク コードは、ページ アウトされたページにアクセスできません。管理者特権でのコマンド プロンプトから次のコマンドを実行すると、このレジストリ キーが設定されます。
このレジストリ キーを設定したら、コール スタックを記録する前にシステムを再起動する必要があります。このフラグを設定すると、Windows カーネルがより多くのページを RAM にロックすることになるため、おそらく約 10 MB の追加の物理メモリが消費されます。
これは、64 ビット Windows (および 64 ビット Windows のみ) では、ディスク上にページ アウトが存在する可能性があるため、カーネル スタックをウォークできないという印象を与えます。
winapi - 特定の関数で/EHscを使用して/EHaの利点を得る方法は?
extern "C"
プログラム内の特定の関数(たとえばRaiseException
)がSEH例外を発生させる唯一の関数であり、それらをC ++例外に変換したい場合/EHa
、その関数を「選択的に有効にする」方法はありますか。例外は、通常は?によって引き起こされるCStructured_Exception
ように、プログラムの残りの部分を肥大化させたり遅くしたりせずに変換されます。/EHa
c++ - _set_se_translator の「get」に相当するものは?
現在のトランスレータを使用して、構造化例外を手動で翻訳する必要があります。
誰かが設定した値を「取得」するにはどうすればよい_set_se_translator
ですか?
c++ - 外部エラーコードのstd::error_conditionへのマッピング
MS構造化例外から例外へのマッピングコードを変更することを検討しています。新しいC++11 error_code / error_condition/exceptionメカニズムを使用する必要があります。
私の理解では、一般的な考え方では、最初にエラーコードをstd :: error_conditionコードにマップしてみてください。それができない場合は、独自のカスタムerror_conditionコードを作成してください。
std :: errcは、POSIXエラーでうまく機能するように調整されていることがわかりました。通常のOS呼び出しとはかなり異なるエラーユニバースを持つソースからコードを取得している場合、それはうまくマッピングされません。
たとえば、MicrosoftのSEHコードを見てみましょう。これらはOSからのものであるため、理論的には、POSIX以外のすべてのものと同様にマップする必要があります。しかし、それは確かにまったくうまくマッピングされていないようです:
では、これを攻撃する最善の方法は何でしょうか?
visual-c++ - Visual Studio C ++でアクセス違反を処理するにはどうすればよいですか?
通常、アクセス違反はプログラムを終了し、とを使用してWin32例外をキャッチできませtry
んcatch
。アクセス違反が発生した場合でも、プログラムを実行し続ける方法はありますか?できれば、例外を処理して、アクセス違反が発生したことをユーザーに示したいと思います。
編集:プログラミングエラーに対しても、プログラムを本当に堅牢にしたいです。私が本当に避けたいのは、破損した状態を犠牲にしてもプログラムの終了です。
c++ - MiniDumpWriteDump() を呼び出してクラッシュをキャッチするのに最適な場所
私が維持している大規模な Win32 プログラムがあり、何か問題が発生するたびに自動的かつ無条件にミニダンプ ファイルを生成するようにインストルメント化したいと考えています。顧客に userdump.exe のインストールを依頼することはできず、Visual Studio のインストールを依頼することもできません。
これを行う良い方法はありますか?アサート ハンドラーから abort() が呼び出された場合 (これは複雑です)、誰かが不良メモリに触れた場合、またはその他の本当に悪いことが発生した場合に、ミニダンプを生成できるようにしたいと考えています。
Posix では、シグナル ハンドラーをインストールして、これで完了です。私の理解では、Windows での同等のアプローチは SEH ですが、私たちのプログラムはさまざまな場所で多くのスレッドを起動するため、すべてのスレッド エントリ ポイントを __try/__catch でラップするのは非常に困難です。
アイデア?
c++ - 構造化例外処理でキャッチされた例外を COM 経由で公開するにはどうすればよいですか?
Visual C++ で実装された私の COM サーバーは、他の大量の C++ コードを使用しています。他の C++ コードは、コードをラップして、構造化例外をカスタム C++ 例外に変換することが__try
あり__except
ます。この部分は私には変えられません。
私の COM サーバーのメソッドは、これらの例外が COM 境界を介して伝播することを許可しないため、それらをキャッチしてHRESULT
s に変換する必要があります。これらのカスタム C++ 例外には、変換中に取得された元のエラー コードが含まれていますEXCEPTION_ACCESS_VIOLATION
。問題は、クライアントが何が起こったのかについて可能な限り多くの情報を取得できるように、適切なHRESULT
値をどのように作成するかです (そして、アクセス違反を見た後にサーバー (および inproc の場合はそれ自体) を再起動することを決定する可能性があります)。
EXCEPTION_ACCESS_VIOLATION
で定義されているとします。WinBase.h
後者はで定義されていますWinNT.h
そもそもWin32 エラーであると仮定して、HRESULT_FROM_WIN32()
そのコードを変換するために使用できます。HRESULT
HRESULT_FROM_WIN32()
ここで翻訳を行うべきですか、それとも他の方法を使用して翻訳を行うべきですか?
c++ - __finally は EXCEPTION_CONTINUE_SEARCH の後に実行することになっていますか?
次のコードでは、関数foo
は自分自身を再帰的に 1 回呼び出します。内部呼び出しにより、アクセス違反が発生します。外部呼び出しが例外をキャッチします。
ここで期待される出力は
ただし、outer finally 0
実際の出力からは著しく欠落しています。これはバグですか、それとも見落としている詳細がありますか?
完全を期すために、VS2015 で発生し、x64 用にコンパイルします。驚くべきことに、x86 では発生しないため、これは本当にバグだと思います。