Win32構造化例外の概要 - inoueshinichi/Wiki_Windows GitHub Wiki

参考

所感

オブジェクト指向が発展していない時代にMicrosoftが開発した構造体(struct)を用いた例外処理メカニズムっぽい. 現在のC++言語では標準のstd::exceptionクラスとその派生クラス群で管理されているから必要とする場面はごく一部だと思われる.

構造化例外

ハードウェア由来とソフトウェア由来の例外を処理するメカニズム. カーネルモード・ユーザーモードのどちらも一括処理できる.

  • ハードウェア由来・・・CPUから発行される. ゼロ除算, ダングリングポインタへのアクセス etc
  • ソフトウェア由来・・・アプリケーションまたはオペレーティングシステムから発行される.

特徴

  • 構造化例外処理はコンパイラのサポートを受けて実現する.
  • MSVC(VC+)では, __try, __except, __finally, __leaveを提供している.
  • スレッド例外を発行できるようにRaiseException関数が提供されている.
  • スレッドの状態はCONTEXT構造体に, 例外情報はEXCEPTION_RECORD構造体に保存される.
  • アプリケーション側では, GetExceptionInformation関数を用いてCONTEXT構造体とEXCEPTION_RECORD構造体にアクセスできる.
  • ユーザーモードで例外が発生した場合とカーネルモードで例外が発生した場合で, その後の処理フローは異なる. (だけど, アプリケーション側からは同じ処理で大丈夫)
  • ユーザーモードで例外が発生した際にデバッカーが起動していれば, デバッカーを通じて様々な処理が可能.
  • 浮動小数点例外(FP例外)はデフォルトで無効. オプションで有効にできる.
  • フレームベース例外処理, ベクターベース例外処理, 終了処理の3種類の処理方法がある.

例外情報EXCEPTION_RECORD構造体が含む情報

  • 例外の種類を識別する例外コード
  • 例外が継続可能かどうかを示すフラグ. 非コンティニュアブル例外の後に実行を続行しようとすると別の例外が生成される.
  • 別の例外レコードへのポインター. 入れ子になった例外が発生した場合にリンクされた例外リストの作成が容易になる.
  • 例外が発生したアドレス.
  • 例外に関する追加情報を提供する引数の配列.

例外発生後のフロー

  1. ハードウェアorソフトウェア由来の例外が発生
  2. プロセッサが例外をキャッチしてシステム(OS)に転送
  3. システムは例外の発生したスレッドの状態と例外情報を保存する
  4. システムは該当する例外ハンドラーを検索する
  5. 例外の発生したアプリケーションで例外をスローする

ハンドラー構文

Exception-Handler構文(フレームベース例外処理)

__try
{
    /*body*/
}
__exception(filter-exception)
{
    /*exception process*/
}

※ C++標準の処理方法と同じ.

Termination-Handler構文(終了処理)

__try
{
    /*body*/
}
__finaly
{
   /*final process*/
}

※ 終了ハンドラーを構築するため使用する.

Vector-Handler構文?(ベクターベース例外)

LONG WINAPI VectorHandler1(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
  /* except process [1] */
}

LONG WINAPI VectorHandler2(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
  /* except process [2] */
}

...

LONG WINAPI VectorHandlerSkip1(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
  /* ??? */
}

...


// main
PVOID h1, h2, h3;
LONG e[3];
e[0]=1; e[1]=2; e[2]=3;
h1 = AddVectoredExceptionHandler(CALL_FIRST, VectorHandler1);
h2 = AddVectoredExceptionHandler(CALL_FIRST, VectorHandler2);
h3 = AddVectoredExceptionHandler(CALL_LAST, VectorHandlerSkip1);

__try
{
  RaiseException(1,0,0,NULL);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
  /* exception process */
}

RemoveVectoredExceptionHandler(h1);
RemoveVectoredExceptionHandler(h2);
RemoveVectoredExceptionHandler(h3);