NT_ASSERTマクロ

ドライバ開発の際には従来広くASSERTマクロが使われているが、最近のWDKではASSERT定義周辺に、NT_ASSERTというマクロが追加されている。このマクロは現時点では文書化されていないものの、ASSERT Yourself - The New NT_ASSERT Macro in the WDKにおいて、詳細に独自研究されている。

ここでは以下にこの文書の要約を示す。

ASSERTと同じ点

  1. DBGが定義されていなければ(つまりFree Buildであるならば)完全に消去される。
  2. 渡した条件式がFALSEになるとカーネルデバッガにトラップされる。
  3. その状況でカーネルデバッガが接続されていないとBSODになる。

ASSERTと異なる点

  1. __annotation組み込み命令を使い、条件式中の文字列をPDB側に埋め込む(バイナリには埋め込まない)。
  2. Vista以降でしかトラップ(ブレーク)が機能しない。
  3. Vista以降では、トラップが発生したとき、カーネルデバッガプロンプトを表示させ「以後このアサーションを無視する」事を指示する機会が与えられる(従来の Ignore はその場限りの無視)。


重要なのは、2,3番目。3番目がこのマクロの価値のある部分で、2番が重大な制約である。
このようになっている理由は、NT_ASSERTマクロ内部で利用されているDbgRaiseAssertionFailure関数にある。従来のASSERTマクロはRtlAssert関数を用い、内部ではDbgPromptを経由してDbgBreakPoint(INT 3)を実行するが、このDbgRaiseAssertionFailureはただ INT 2C 命令を実行する。その結果、IDT 0x2C番のハンドラが実行され、Vista以降ではこの中(KiRaiseAssertion)で専用のソフトウェア例外を生成して専用の処理をデバッガに任せることができる。一方XP以前では、IDT 0x2C番にこのハンドラが実装されていない(KiSetLowWaitHighThreadという関係のない関数)ため、まったく機能しない。

この差異はユーザーモードからも確認することができる。以下の画像のコードはVista以降では例外を発生させるが、XPまでは何も起こらず正常終了する。画像はVistaで実行させたもの。
 


どちらを選択するかは、お好みで。私はXPでデバッグすることが多いので、使わない。