デバッガーで実行すると、最近かなり奇妙な動作を示し始めた大規模なアプリケーションがあります。まず、基本:
OS: Windows 7 64-bit.
Application: Multithreaded VCL app with many dlls, bpls, and other components.
Compiler/IDE: Embarcadero RAD Studio 2010.
観測された症状は次のとおりです。デバッガーがアプリケーションに接続されている間、特定のタスクが原因でアプリケーションがクラッシュします。詳細はさらに複雑です。私のアプリケーションは、「YourApplication has stopped working」という Windows メッセージで停止します。また、Microsoft にミニダンプを送信することもできます。
注意してください: デバッガーが接続されていない場合、アプリケーションはクラッシュしません。また、デバッガーは、アプリケーションの実行中に例外やその他の問題を示しません。
ブレークポイントの設定とステップスルーは、アプリケーションがクラッシュするポイントに影響を与えるようですが、問題のあるスレッド以外のスレッドをデバッグすることの兆候であると思われます。
これらのクラッシュは同僚のコンピューターでも発生し、私が観察したのと同じ動作です。これにより、特にコンピューターへのインストールの失敗を疑うことはありません。この問題が発生している同僚も Windows 7 64 ビットを実行しています。この問題を経験していない同僚はいません。
クラッシュから分析された多数の完全なダンプを収集しました。失敗は実際には毎回同じ場所で起こっていることがわかりました。ダンプからの例外データを次に示します (もちろん、ThreadId を除いて常に同じです)。
Exception Information
ThreadId: 0x000014C0
Code: 0x4000001F Unknown (4000001F)
Address: 0x773F2507
Flags: 0x00000000
NumberParameters: 0x00000001
0x00000000
Google は、コード 0x4000001F が実際には STATUS_WX86_BREAKPOINT であることを明らかにしています。Microsoft は、これを「Win32 x86 エミュレーション サブシステムで使用される例外ステータス コード」と表現しています。
スタックの詳細は次のとおりです (変化しないようです)。
0x773F2507: ntdll.dll+0x000A2507: RtlQueryCriticalSectionOwner + 0x000000E8
0x773F3DAB: ntdll.dll+0x000A3DAB: RtlQueryProcessLockInformation + 0x0000020D
0x773D2ED9: ntdll.dll+0x00082ED9: RtlUlonglongByteSwap + 0x00005C69
0x773F3553: ntdll.dll+0x000A3553: RtlpQueryProcessDebugInformationRemote + 0x00000044
0x74F73677: kernel32.dll+0x00013677: BaseThreadInitThunk + 0x00000012
0x77389F02: ntdll.dll+0x00039F02: RtlInitializeExceptionChain + 0x00000063
0x77389ED5: ntdll.dll+0x00039ED5: RtlInitializeExceptionChain + 0x00000036
0x773F24ED に関数のエピローグがあるように見えることは注目に値します。これはむしろ、RtlQueryCriticalSectionOwner が重要人物であることを示唆しています。同様に、関数のエピローグは RtlQueryProcessLockInformation に疑問を投げかけます。0x5C69 オフセットは、RtlUlonglongByteSwap に疑問を投げかけます。ただし、他のシンボルは正当に見えます。
具体的には、RtlpQueryProcessDebugInformationRemote は正当に見えます。インターネット上の一部の人々 ( http://www.cygwin.com/ml/cygwin-talk/2006-q2/msg00050.html ) は、デバッグ情報を収集するためにデバッガーによって作成されたと考えているようです。デバッガーが接続されている場合にのみ表示されるように見えるため、その理論は私には適切に思えます。
いつものように、何かが壊れると、それを壊した何かが変わります。この場合、何かが新しい dll を動的にロードしています。特定の dll を動的にロードしないことで、クラッシュの発生を停止させることができます。dll の読み込みが関連しているとは確信していませんが、念のために詳細を以下に示します。
dll ソースは C です。デフォルトに設定されていないコンパイル オプションは次のとおりです。
Language Compliance: ANSI
Merge duplicate strings: True
Read-only strings: True
PCH usage: Do not use
Dynamic RTL: False
(プロジェクト オプションでは、Dynamic RTL のデフォルトは False と表示されていますが、dll プロジェクトを作成したときに True に設定されていました。)
dll は LoadLibrary でロードされ、FreeLibrary で解放されます。モジュールのロードとアンロードはすべて問題ないようです。ただし、ライブラリが (FreeLibrary で) アンロードされた直後に、前述のスレッドがプログラムをクラッシュさせます。デバッグのために、ライブラリへの実際の呼び出しをすべて削除しました (さらにテストするために、DllMain を含む)。呼び出しの組み合わせ、呼び出しなし、DllMain の組み合わせ、または DllMain なし、またはその他の組み合わせは、クラッシュの動作を変更するようには見えませんでした。dll をロードおよびアンロードするだけで、後でクラッシュが発生します。
さらに、動的 RTL を使用するように dll を変更すると、デバッガー スレッドのクラッシュも停止します。コンパイルされた dll は、CodeGear ランタイムがなくても実際に使用できるはずなので、これは望ましくありません。また、dll のサイズも重要です。dll に含まれる C コードは、ライブラリを使用しません。(ヘッダーは含まれません。標準ライブラリのヘッダーも含まれます。malloc/free、printf、nothin' は含まれません。入力にのみ依存し、動的割り当てを必要としない関数のみが含まれます。)なぜ機能するのかを理解せずに、機能するまで何かを変更してバグを修正することは、決して良い計画ではありません。(それはバグの再発や奇妙なコーディング慣行につながる傾向があります。しかし、実際には、この時点で他に何も見つからない場合は、この点で敗北を認めるかもしれません.)
最後に、私の問題は次のいずれかの問題に関連している可能性があります。
アイデアや提案をいただければ幸いです。