Microsoft固有の例外処理メカニズム

Microsoft Windowsファミリのオペレーティング システムでは、いくつかの特定の例外処理メカニズムが採用されています。

構造化例外処理

Microsoft構造化例外処理は、Windowsのネイティブ例外処理メカニズムであり、ベクトル例外処理(VEH)の前身となる技術です。[ 1 ]標準C++例外には存在しないメカニズム(ただし、後に導入されるほとんどの命令型finally言語には存在します)を備えています。SEHは実行スレッドごとに個別に設定および処理されます。

使用法

Microsoftは、SEHをコンパイラレベルでのみプログラミング手法としてサポートしています。MS Visual C++コンパイラには、この目的のために、__try__except__finally— という3つの非標準キーワードが用意されています。その他の例外処理は、いくつかのWin32 API関数によってサポートされており、[ 2 ]、例えばRaiseExceptionSEH例外を手動で発生させることができます。

int filterExpression ( EXCEPTION_POINTERS * ep ) { ep -> ContextRecord -> Eip += 8 ; // 除算命令は2~8バイトでエンコードされる可能性がありますreturn EXCEPTION_CONTINUE_EXECUTION ; }int main ( void ) { static int zero = 0 ; __try { zero = 1 / zero ; asm { nop nop nop nop nop nop nop nop } printf ( "例外を過ぎました。\n " ); } __except ( filterExpression ( GetExceptionInformation ())) { printf ( "ハンドラーが呼び出されました。\n " ); } return 0 ; }

実装

IA-32

Windows IA-32エディションまたはx86-64バージョンのWoW64エミュレーション レイヤーの各実行スレッドには、スレッド情報ブロックの先頭に、ドキュメント化されていない_EXCEPTION_REGISTRATION_RECORDリストへのリンクがあります。文は基本的にコンパイラ定義の関数を呼び出します。その関数は、スタック上に[ a ]関数を指す_EXCEPTION_REGISTRATION_RECORDを割り当て、[ b ]はレコードをリストの先頭に追加します。ブロックの最後では、逆の操作を行うコンパイラ定義の関数が呼び出されます。これらのコンパイラ定義のルーチンはどちらもインライン にすることができます。プログラマ定義のブロックとブロックはすべて、 内から呼び出されます。プログラマ定義のブロックが存在する場合、によって作成された_EXCEPTION_REGISTRATION_RECORDは、によって使用されるいくつかの追加フィールドで拡張されます。[ 3 ]__tryEH_prolog__except_handler3msvcrt.dll__tryEH_epilog__except__finally__except_handler3EH_prolog__except_handler3

ユーザーモードコードで例外が発生した場合、オペレーティングシステムは[ c ]スレッドの_EXCEPTION_REGISTRATION_RECORDリストを解析し、各例外ハンドラを順番に呼び出します。これは、ハンドラが例外を処理したことを示す(戻り値)か、リストの最後まで呼び出されるまで続きます。リストの最後は常に であり、一般保護違反エラーメッセージが表示されます。 [ d ]その後、リストがもう一度走査され、ハンドラは使用されたリソースをクリーンアップする機会を得ます。最後に、実行はカーネルモードに戻り[ e ]、プロセスは再開または終了します。 kernel32!UnhandledExceptionFilter

このモードの SEH に関する特許 (US5628016) は 2014 年に失効しました。

x86-64

64ビットWindowsのSEHは、実行時例外ハンドラリストを必要としません。代わりに、例外発生時にシステムによって解釈されるスタックアンワインドテーブル( )を使用します。 [ 4 ] [ 5 ] つまり、コンパイラは手動でスタックアンワインドを実行し、例外ハンドラを適切に呼び出すための追加コードを生成する必要がありません。コンパイラは、スタックフレームのレイアウトと指定された例外ハンドラに関する情報を、アンワインドテーブルの形式で出力するだけで済みます。 UNWIND_INFO

サポート

Mingw-w64のGCC 4.8+は、C++例外に64ビットSEHの使用をサポートしています。LLVM clangはx86とx64の両方でサポートしています__try[ 6 ]

ベクトル例外処理

ベクトル例外処理はWindows XPで導入されました。[ 7 ]ベクトル例外処理は、C++Visual Basicなどの言語を使用するWindowsプログラマーに提供されています。VEHは構造化例外処理(SEH)に取って代わるものではなく、VEHとSEHは共存し、VEHハンドラーはSEHハンドラーよりも優先されます。[ 1 ] [ 7 ] SEHと比較すると、VEHはカーネルから配信されるUnixシグナル のように動作します。[ 8 ]

注記

  1. ^ VCランタイムのバージョンによって名前は異なります
  2. ^ntdll.dllおよびkernel32.dll、VCランタイムに静的にリンクされた他のプログラムでは、代わりにこの関数がコンパイルされている。
  3. ^具体的には、ntdll!RtlDispatchExceptionシステム ルーチンから呼び出され、ntdll!KiUserExceptionDispatcherそのシステム ルーチンがカーネル関数から呼び出されますnt!KiDispatchException。( Ken Johnson (2007 年 11 月 16 日) を参照してください。「NTDLL カーネル モードからユーザー モードへのコールバックのカタログ、パート 2: KiUserExceptionDispatcher」)詳細は
  4. ^プロセスのエラーモードを変更することでメッセージを消すことができます。デフォルトの最後のハンドラはSetUnhandledExceptionFilter APIで置き換えることができます。
  5. ^ は、またはのntdll!KiUserExceptionDispatcherいずれかを呼び出しますnt!ZwContinuent!ZwRaiseException

参考文献

  1. ^ a b「Windows Server 2003 におけるベクトル例外処理(インターネットアーカイブ経由)」。 2008年1月18日時点のオリジナルよりアーカイブ。
  2. ^ Microsoft Corp. (2009-11-12). 「構造化例外処理関数」 . MSDN ライブラリ. 2022年7月23日閲覧
  3. ^ Peter Kleissner (2009年2月14日). 「Windows Exception Handling - Peter Kleissner」 . 2013年10月14日時点のオリジナルよりアーカイブ。 2009年11月21日閲覧コンパイラベースの構造化例外処理セクション
  4. ^ 「例外的な動作 - x64 構造化例外処理」。The NT Insider。
  5. ^ 「x64例外処理」 . VC++ 2019ドキュメント. 2022年2月8日.
  6. ^ 「MSVC互換性」。Clang 11ドキュメント
  7. ^ a b「Under the Hood: Windows XP の新しいベクトル例外処理」 。2008年9月15日時点のオリジナルよりアーカイブ
  8. ^ 「Windows Server 2003 Discover 改善されたシステム情報、新しいカーネル、デバッグ、セキュリティ、UI API」 。2008年5月5日時点のオリジナルよりアーカイブ