アクセス違反 - まずはスタックバックトレースから
アクセス違反などでクラッシュして終了したプロセスのダンプをデバッガで開くと、 クラッシュしたスレッドにコンテキストがセットされた状態で開かれます。 このため、ひとめみただけで、クラッシュの直接の原因を特定することが可能です。
その直接の原因にいたる経緯はひとめではわかりませんが、なぜアクセス違反を発生させたのか、などは ひとめでわかります。
「ひとめでわかる」 と言われても、デバッガを使ったことが無ければ、 なかなかピンとこないと思いますので、簡単な例をみてください。
クラッシュ時の解析例
次のようなコードがあったとします。
#include <string.h> int main() { strcpy( NULL, NULL ); return 0; }
このコードでは strcpy 関数を呼び出していますが、文字列の元のアドレスも書き込み先も NULL がセットされています。 NULL で指し示される 0x00000000 番地は読込み、書き込み禁止ですから、このプログラムを実行するとアクセス違反が発生します。
試しにプログラムをビルドして、実行すると確かに次のように致命的エラーの発生を示すダイアログボックスが表示されます。
このサンプルでは、何しろコードがクラッシュするコードしか無いのでどこで問題が発生するか明らかではありますが、 これがデバッガではどのように見えるか確認してみましょう。
デバッガをアタッチして、プログラムを実行します。
C:\Temp\debug>c:\debuggers\cdb crashtest.exe Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: crashtest.exe Symbol search path is: srv*C:\websymbols*http://msdl.microsoft.com/download/symbo Executable search path is: ModLoad: 00400000 00417000 crashtest.exe ModLoad: 77a00000 77b3c000 ntdll.dll ModLoad: 77070000 77144000 C:\Windows\system32\kernel32.dll ModLoad: 75d40000 75d8a000 C:\Windows\system32\KERNELBASE.dll (e6c.17e0): Break instruction exception - code 80000003 (first chance) eax=00000000 ebx=00000000 ecx=0012fb0c edx=77a464f4 esi=fffffffe edi=00000000 eip=77a9e60e esp=0012fb28 ebp=0012fb54 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!LdrpDoDebuggerBreak+0x2c: 77a9e60e cc int 3 0:000> g
プログラムを続行すると、次のようにアクセス違反 (Access Violation, AV) で停止します。
(e6c.17e0): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=003b2408 ebx=7ffdf000 ecx=00000000 edx=7efefeff esi=00000000 edi=00000000 eip=004010c3 esp=0012ff30 ebp=0012ff40 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246 crashtest!strcat+0x93: 004010c3 8b01 mov eax,dword ptr [ecx] ds:0023:00000000=????????
ここで ecx が 00000000 であり、それを読み出そうとしたことがアクセス違反を発生させていることがわかります。
kbn コマンドでスタックバックトレースをみると、strcat 内のコードであることがわかります。
0:000> kbn # ChildEBP RetAddr Args to Child 00 0012ff88 770c1174 7ffdf000 0012ffd4 77a5b3f5 crashtest!strcat+0x93 01 0012ff94 77a5b3f5 7ffdf000 7dd2d31f 00000000 kernel32!BaseThreadInitThunk+0xe 02 0012ffd4 77a5b3c8 004012da 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70 03 0012ffec 00000000 004012da 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b 0:000>
また、デバッガをアタッチしている状況でなくても、Windows Error Report (WER) のレジストリを構成しておけば、 プログラムがクラッシュしたときに自動的にユーザーダンプを採取することが可能です。このダンプを解析することによって、 原因を追究することが可能です。
WER ではデフォルトのダンプ出力フォルダは %LOCALAPPDATA%\CrashDumps なので、そこにあるダンプを確認します。
-z オプションでダンプファイルを指定して、cdb でユーザーダンプを開くと次のようになります。
>c:\debuggers\cdb -z C:\Users\Keisuke\AppData\Local\CrashDumps\crashtest.exe.3752.dmp Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [C:\Users\Keisuke\AppData\Local\CrashDumps\crashtest.exe.3752.dmp] User Mini Dump File with Full Memory: Only application data is available Symbol search path is: srv*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: Windows 7 Version 7600 MP (2 procs) Free x86 compatible Product: WinNt, suite: SingleUserTS Machine Name: Debug session time: Thu Feb 4 23:29:50.000 2010 (GMT-8) System Uptime: 2 days 1:07:19.703 Process Uptime: 0 days 0:00:03.000 .... This dump file has an exception of interest stored in it. The stored exception information can be accessed via .ecxr. (ea8.1288): Access violation - code c0000005 (first/second chance not available) eax=00000000 ebx=0012f934 ecx=00000400 edx=00000000 esi=00000002 edi=00000000 eip=77a464f4 esp=0012f8e4 ebp=0012f980 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 77a464f4 c3 ret 0:000> .ecxr eax=00581be8 ebx=7ffdf000 ecx=00000000 edx=7efefeff esi=00000000 edi=00000000 eip=004010c3 esp=0012ff30 ebp=0012ff40 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246 crashtest!strcat+0x93: 004010c3 8b01 mov eax,dword ptr [ecx] ds:0023:00000000=???????? 0:000> kbn *** Stack trace for last set context - .thread/.cxr resets it # ChildEBP RetAddr Args to Child 00 0012ff88 770c1174 7ffdf000 0012ffd4 77a5b3f5 crashtest!strcat+0x93 01 0012ff94 77a5b3f5 7ffdf000 7d35df4c 00000000 kernel32!BaseThreadInitThunk+0xe 02 0012ffd4 77a5b3c8 004012da 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70 03 0012ffec 00000000 004012da 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b 0:000>
詳細は省きますが、上記のようにライブデバッグの時と同様のログが確認できることがお分りいただけると思います。