以前就发现LH的Exception Handling有变化。当程序崩溃后,程序会被系统挂在发生问题的汇编代码上,这样直接用调试器上去就可以看了。当时一直想研究下具体怎么实现的。另外在<Windows高效排错中>具体的异常派发也没有详细地用调试器走一遍。今天有时间,所以就用调试器跑了一遍一个简单的AV。
我最佩服的Windows用户态代码有两个。其中一个是异常派发,另外一个是CLR引擎。异常派发的代码加在一起,估计也不会超过5000行。但是异常派发这个东西从用户态到核心态,从C++到CLR,跟系统相关,跟编译器相关,跟调试器相关,跟编译选项相关,跟系统安全设置相关,跟注册表设定相关...我了解AEDebug,了解UnhandledExceptionFilter,了解/EHa,了解FIEO,了解windbg,了解__try/__except,可以我也从来没能够把整个异常派发的流程完整地调过一遍。
下面的代码非常简单,就是一个普通的AV。大家看看有多复杂。我尽可能地理清了用户态的流程和关键函数。但是对于其中的具体环节,比如stack frame怎么恢复,trylevel怎么遍历,stack unwind怎么实现等等,都没有具体深入。如果有兴趣的可以看看中间的过程,没有兴趣的可以直接到最后看结论。
代码非常简单

#include "windows.h"
class dummy
{
public:
 ~dummy(); 
};
dummy::~dummy()
{
 MessageBox(0,L"aaa",0,0);
};
int _tmain(int argc, _TCHAR* argv[])

 dummy d;
 char c=getchar();
 if(c=='2')
  SetErrorMode(2);
 if(c=='3') 
  throw 1; 
 int *p=0;
 int j=*p;
 printf("%d/n",j); 
 return 0;
}
运行后,输入字符5,使得j=*p发生Access Violation。下面是异常发生后的处理。系统是Longhorn Server RC1。
首先自然是让AV触发了:
0:001> g
(ec8.978): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=7ffd4000 ecx=47c1164d edx=00496008 esi=00000000 edi=0012ff1c
eip=0042ecfa esp=0012fe2c ebp=0012ff1c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
*** WARNING: Unable to verify checksum for crashstudy.exe
*** ERROR: Module load completed but symbols could not be loaded for crashstudy.exe
crashstudy+0x2ecfa:
0042ecfa 8b08            mov     ecx,dword ptr [eax]  ds:0023:00000000=????????
接下来的端点是在ntdll!KiUserExceptionDispatcher。因为用户态的异常,会直接被核心通过这个函数派发出来。
这个核心函数非常简单,就是几行汇编。这个函数首先通过FS寄存器寻找Exception handler head,得到的head如下:
0:000> kL
ChildEBP RetAddr 
0012fc10 77148107 ntdll!RtlDispatchException+0x3a
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

0:000> r
eax=0012ff2c ebx=0012fc28 ecx=0012fc04 edx=0012fb8c esi=0012fc28 edi=00001771
eip=77126612 esp=0012fba0 ebp=0012fc10 iopl=0         nv up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000283
ntdll!RtlDispatchException+0x3a:
77126612 8365f000        and     dword ptr [ebp-10h],0 ss:0023:0012fc00=0012fb38
0:000> dt EXCEPTION_REGISTRATION_RECORD  0012ff2c
   +0x000 Next             : 0x0012ff78 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x0040b1a5     crashstudy!_EH_prolog3_catch+0
0:000> dt EXCEPTION_REGISTRATION_RECORD  0x0012ff78
   +0x000 Next             : 0x0012ffc4 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x00402550     crashstudy!_except_handler4+0
0:000> dt EXCEPTION_REGISTRATION_RECORD  0x0012ffc4
   +0x000 Next             : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x770fa033     ntdll!_except_handler4+0
从上面的输出可以看到,三个异常处理函数分别是crashstudy!_EH_prolog3_catch,rashstudy!_except_handler和ntdll!_except_handler4。注意名字,前两个是编译器编译到程序中的,最后一个是系统默认的最后一环异常处理函数。用!exchain命令可以更直观地输出结果:
0:000> !exchain
0012ff2c: crashstudy!_EH_prolog3_catch+47 (0040b1a5)
0012ff78: crashstudy!_except_handler4+0 (00402550)
0012ffc4: ntdll!_except_handler4+0 (770fa033)

首先触发的当然就是_EP-prolog3_catch了:
0:000> kL
ChildEBP RetAddr 
0012fb60 7714827b crashstudy!_EH_prolog3_catch+0x47
0012fc10 77148107 ntdll!ExecuteHandler+0x24
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
crashstudy!_EH_prolog3_catch函数的目的是什么呢,请看:
0:000> kL
ChildEBP RetAddr 
0012facc 0040b015 crashstudy!FindHandler+0x336
0012fb00 00409fcd crashstudy!__InternalCxxFrameHandler+0xd9
0012fb3c 771482a9 crashstudy!__CxxFrameHandler3+0x26
0012fb60 7714827b ntdll!ExecuteHandler2+0x26
0012fc10 77148107 ntdll!ExecuteHandler+0x24
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
注意看,这里一路调上来,就到了FindHandler函数。这是C Runtime中非常重要的函数。比如说:
0:000> u crashstudy!FindHandler+0x27c
crashstudy!FindHandler+0x27c
0040ae4a 6a01            push    1
0040ae4c 56              push    esi
0040ae4d e837f7ffff      call    crashstudy!__DestructExceptionObject (0040a589)
0040ae52 59              pop     ecx
0040ae53 59              pop     ecx
0040ae54 807dff00        cmp     byte ptr [ebp-1],0
0040ae58 0f85ae000000    jne     crashstudy!FindHandler+0x33e (0040af0c)
0040ae5e 8b07            mov     eax,dword ptr [edi]
C++相关的异常派发,stack object的析构,就是在这里完成。这里由于发生的异常是AV,所以找C++ handler是找不到的。找不到的结果呢,就是程序就会退回到
0:000> kL
ChildEBP RetAddr 
0012fc10 77148107 ntdll!RtlDispatchException+0x124
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
既然没有找到对应的handler,RtlDispatchException函数继续寻找了。这次当然就会来到crashstudy!_except_handler4:

0:000> kL
ChildEBP RetAddr 
0012fb3c 771482a9 crashstudy!_except_handler4
0012fb60 7714827b ntdll!ExecuteHandler2+0x26
0012fc10 77148107 ntdll!ExecuteHandler+0x24
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
这个_except_handler4函数有什么用呢,这个函数的作用不比寻找C++ exception handler的作用小。这里先不说有什么用,大家只要记得,这个函数一路调用过去,最后的callstack会成为这样。
0:000> kL
ChildEBP RetAddr 
0012fa48 7702ea1d crashstudy!__CxxUnhandledExceptionFilter
0012fad4 00402d34 kernel32!UnhandledExceptionFilter+0x137
0012faf4 004013d9 crashstudy!_XcptFilter+0x6a
0012fb00 00405280 crashstudy!__tmainCRTStartup+0x188
0012fb14 004025de crashstudy!_EH4_CallFilterFunc+0x12
0012fb3c 771482a9 crashstudy!_except_handler4+0x8e
0012fb60 7714827b ntdll!ExecuteHandler2+0x26
0012fc10 77148107 ntdll!ExecuteHandler+0x24
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
注意哦,这里的crashstudy!__tmainCRTStartup出现了两次,最后会调用到crashstudy!_XcptFilter这个函数以及kernel32!UnhandledExceptionFilter函数。这一系列的调用有什么用呢,等下再说。总之这里暂时没有_except_handler4什么事情。于是调用又会回到RtlDispatchException函数继续寻找。
0:000> kL
ChildEBP RetAddr 
0012fc10 77148107 ntdll!RtlDispatchException+0xcb
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
接下来的callstack就比较奇怪了:
0:000> kL
ChildEBP RetAddr 
0012faf8 77167323 kernel32!UnhandledExceptionFilter+0xb0
0012fb00 770fa214 ntdll!__RtlUserThreadStart+0x6f
0012fb14 770f44fc ntdll!_EH4_CallFilterFunc+0x12
0012fb3c 771482a9 ntdll!_except_handler4+0x8e
0012fb60 7714827b ntdll!ExecuteHandler2+0x26
0012fc10 77148107 ntdll!ExecuteHandler+0x24
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
kernel32!UnhandledExceptionFilter又执行了一次。不过这次不是通过crashstudy!_XcptFilter执行的了。这次还是没有找到对应的handler,由于所有的handler都尝试完了,所以这次就回到了
0:000> kL
ChildEBP RetAddr 
0012ff38 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
这个时候ntdll!KiUserExceptionDispatche作了一个让我非常惊讶的事情。他居然去调用了ntdll!ZwRaiseException,让这个Access Violation再发生一次!
0:000> u eip
ntdll!KiUserExceptionDispatcher+0x20
77148118 59              pop     ecx
77148119 6a00            push    0
7714811b 51              push    ecx
7714811c 53              push    ebx
7714811d e84ef2ffff      call    ntdll!ZwRaiseException (77147370)
77148122 83c4ec          add     esp,0FFFFFFECh
77148125 890424          mov     dword ptr [esp],eax
77148128 c744240401000000 mov     dword ptr [esp+4],1
这个时候再去调RaiseException会发生什么暂且不说。现在拿到手的信息有:
1. 三个Exception handler,分别是
crashstudy!_EH_prolog3_catch+47 (0040b1a5)
crashstudy!_except_handler4+0 (00402550)
ntdll!_except_handler4+0 (770fa033)
第一个会去找C++的try/catch block,以及destruct C++的object。第二个和第三个handler有什么用还不清楚。
2. 在第二次和第三次exception handler执行的时候,kernel32!UnhandledExceptionFilter都会执行。这个函数有啥用也还不清楚。
接下来需要继续试验了。重新运行这个程序,这次输入2,让SetErrorMode(2)执行。
这种情况下第一次的异常派发没有变,第二次的异常派法到下面这个callstack的时候,也没有变化:
0:000> kL
ChildEBP RetAddr 
0012fad4 00402d34 kernel32!UnhandledExceptionFilter+0x167
0012faf4 004013d9 crashstudy!_XcptFilter+0x6a
0012fb00 00405280 crashstudy!__tmainCRTStartup+0x188
0012fb14 004025de crashstudy!_EH4_CallFilterFunc+0x12
0012fb3c 771482a9 crashstudy!_except_handler4+0x8e
0012fb60 7714827b ntdll!ExecuteHandler2+0x26
0012fc10 77148107 ntdll!ExecuteHandler+0x24
0012fc10 00401066 ntdll!KiUserExceptionDispatcher+0xf
0012ff38 004013af crashstudy!wmain+0x46
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
变化在于kernel32!UnhandledExceptionFilter这个函数。这个函数会检查ErrorMode。如果ErrorMode不是2,它就返回Continue Search,如果是2,它就返会Execute handler flag。当Execute handler flag返回后,callstack变为:
0:000> kL
ChildEBP RetAddr 
0012f728 7714827b crashstudy!_EH_prolog3_catch+0x47
0012faf0 004052b3 ntdll!ExecuteHandler+0x24
0012fb14 00402674 crashstudy!_EH4_GlobalUnwind+0x15
0012fb3c 771482a9 crashstudy!_except_handler4+0x124
00000000 00000000 ntdll!ExecuteHandler2+0x26
注意看,这个时候_EH_prolog3_catch又开始执行了。但是注意看哦,一个重要的地方就是crashstudy!_EH4_GlobalUnwind函数。另外一个重要的地方就是当前的callstack里面,居然没有crashstudy的main。原因后面再说。如果g的话,会看到MessageBox。这个时候断下来看,会看到下面的callstack:
0:000> kL
ChildEBP RetAddr 
0012f348 765a0b66 ntdll!KiFastSystemCallRet
0012f34c 7658ac92 USER32!NtUserWaitMessage+0xc
0012f380 7658b8ed USER32!DialogBox2+0x202
0012f3a8 765dcc8c USER32!InternalDialogBox+0xd0
0012f448 765dd20e USER32!SoftModalMessageBox+0x69f
0012f598 765dd344 USER32!MessageBoxWorker+0x2c7
0012f5f0 765dd5c0 USER32!MessageBoxTimeoutW+0x7f
0012f610 765dd65c USER32!MessageBoxExW+0x1b
0012f62c 00401011 USER32!MessageBoxW+0x45
0012f640 0040b047 crashstudy!dummy::~dummy+0x11
0012ff38 004013af crashstudy!_NLG_Return
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x15e
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

注意看,这里看不到ntdll!KiUserExceptionDispatcher哦!原因是UnahandledExceptionFilter返回了execute_handler_flag表示找到了handler,这个时候就要准备执行handler啦。handler是什么暂且不说,在执行handler以前呢,首先是要unwind stack.
Unwind stack是什么意思呢。我们知道,代码中如果有try或者__try,catch或者__finally,这里的catch和__finally在异常发生后都会执行的。如果函数有嵌套,每一层的__finally都需要执行。除此以外,每一个function里面的local C++ object都需要destruct。问题在于,catch,__finally和destruct的执行上下文应该是怎样的?比如说有一个C++ object,如果desctuct发生在没有发生异常的时候,callstack中是没有Exception Record,也没有什么KiUserExceptionDispatcher的。但是如果异常发生,为了保证destruct的成功完成,以及__finally等执行上下文跟没有发生异常时候的上下文一致,系统需要把发生异常时候的callstack,“伪装”成没有异常发生时候一样。这里的"伪装",就是通过unwind stack来完成的。unwind stack的意思,就是在异常发生后,执行对应的处理之前,恢复stack的状态,使得stack的状态跟没有异常发生时候一样,这样才能保证程序逻辑的正确运行。
在前面的callstack中,看到了__tmainCRTStartup出现了两次,最后会调用到crashstudy!_XcptFilter这个函数,原因是在__tmainCRTStartup中,CRT使用了__try __except。当异常发生后,系统会调用对应的exception filter去判断__tmainCRTStartup的__try和__except是否可以处理这个异常。所以系统会去执行__tmainCRTStartup中对应的代码,以及__tmainCRTStartup的exception filter函数crashstudy!_XcptFilter。这就是callstack中__tmainCRTStartup出现两次的原因。我们假设这里的异常__tmainCRTStartup可以处理,接下来系统就调用object destructor和__except block。这个时候系统就需要伪装成异常没有发生时候的上下文来执行了,通过unwind,stack会被恢复成异常从来没有发生过的样子,这样才能保证局部变量的访问,函数的返回等等代码逻辑正确执行。这个时候去看callstack的话,ntdll!KiUserExceptionDispatcher都是看不到的。
上面的call stack是unwind 以后的状态,unwind的过程包含destruct C++ object,所以上面才有MessageBox。当MessageBox返回后,callstack的状态变为:

0:000> kL
ChildEBP RetAddr 
0012fef0 00402846 kernel32!ExitProcess
0012fef8 00402a4b crashstudy!__crtExitProcess+0x14
0012ff30 00402a82 crashstudy!doexit+0xb5
0012ff40 004013f1 crashstudy!_exit+0xd
0012ff88 76fd1d02 crashstudy!__tmainCRTStartup+0x1a0
0012ff94 771285eb kernel32!BaseThreadInitThunk+0xe
0012ffd4 771285be ntdll!__RtlUserThreadStart+0x23
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
这里ExitProcess得到调用,程序马上就要退出拉!ExitProcess调用的原因在于__tmainCRTStartup的逻辑。__tmainCRTStartup的逻辑是:
__try
{
winmain();
}
__except ( _XcptFilter() )
{
ExitProcess();
}
由于上面返回了Execute handler flag,所以这里__except里面的内容开始执行,程序就退出了。
总的来说,这里的异常处理逻辑是:
1. 语言相关的异常处理是挂在顶端的。比如C++相关的在crashstudy!_EH_prolog3_catch。如果使用CLR,这里的异常处理函数指向mscorwks。这个函数负责程序所控制的异常派发和处理。语言相关的异常处理一般在这里完成。
2. 跟C/C++库相关的异常处理挂在crashstudy!_except_handler4。这个函数用途很多。它是C/C++ Runtime的异常处理守护函数。所有的unhandled C++ exception到这里就为止了,提供了C/C++ exception default hander。同时C/C++的异常库函数实现,也是在这里完成的。
3. 系统默认的异常处理在ntdll!_except_handler4。所有的未处理异常,最后就会掉到这里。这个函数的实现跟CRT的_except_handler4差不多,另外一个用途就是作为系统函数,如果第三方需要实现自己的异常处理逻辑,比如注册自己的异常处理函数和异常代码,这个系统函数就会做对应的派发。
4. CRT库中并不需要显式地使用上面这些函数。通过__try关键字,C/C++编译器生成了上面相关函数的调用逻辑。C/C++库函数的实现中,只需要简单地用__try把main包起来,然后在__except里面做对应处理就可以了。真正实用到上面函数的,主要是编译器。
5. 当找到异常处理函数后,程序会发生UnWind。只有当UnWind发生的时候,C++ destruc才会得到调用。在前面的第一种情况中,由于一直都没有找到对应的处理函数,所以这里的~dummy是没有得到调用的
6. kernel32!UnhandledExceptionFilter非常重要。Win32相关的异常处理函数逻辑都在这里面。比如SetErrorMode,SetUnhandledExceptionFilter的逻辑,都是依靠这个函数来完成的。在Vista/Longhorn以前,这个函数还负责处理UnhandledException。当发生AV的时候,程序会弹出一个框框,这个逻辑就是在kernel32!UnhandledExceptionFilter中实现的。在以往的系统中,启动AEDebug 中的项目也是在这里。
7. Vista上的异常处理发生了很多改变。一个变化就是前面提到的,如果AV没有处理,KiUserExceptionDispatcher会调用ZWRaiseException再次引发一次。而XP的实现就如前面地六点所描述一样。另外Vista上面新增加了很多安全性检查,防止通过Exceptionhanlder造成攻击。
8. 如果比较NT4到Vista的异常处理实现,会发现其中有翻天覆地的变化。首先是编译器上,VC6,VC2003,VC2005对C++和SEH的支持都不一样。请参考后面的链接。其次是Error Reporting功能。从最开始的Dr. Waston到XP的Error Reporting Service,然后到Vista的Werfault.exe,变化巨大。
9. 今天重新研究这里的异常派发,是因为Vista上对未处理异常的新特性。就是这里的RaiseException再次调用。在XP上,如果程序AV,看到错误界面后,这个时候用调试器上去,看到的信息是kernel32!UnhandledExceptionFilter中显示对话框的逻辑。如果需要找到异常地址,需要手动用调试器恢复。但是Vista上当看到错误信息后,直接上调试器,看到目标进程就停在发生错误的汇编那里。这是通过kernel32!UnhandledExceptionFilter调用ZWRaiseException和内核改变完成的。
10. 如果需要调试异常派发,需要用下面的断点欺骗系统。否则异常就直接发到调试器中来了
kernel32!BasepIsDebugPortPresent+0x2e "r eax=0;g"
11. 只有纯净的C++异常处理才有标准可循。如果把C++异常处理跟SEH混用,或者程序中会发生AV,或者跟CLR异常作interop,不同情况下会有不同的行为。
12. 调试的时候,不是所有的函数都可以随便用调试器断下来的。比如你要是尝试step in到kernel32!BasepIsDebugPortPresent里面,就会发现调试器完全失效。
13. Vista新增的异常处理机制需要跟内核配合。中间通过LPC调用,跟svchost通信,启动Werfault错误报告程序。而目标程序的挂起,是从kernel直接完成的。这里内部机制如何,可能需要配合kd才好研究了。跟传统的Dr. Waston, AEDebug相比,现在的机制非常方便调试人员检查程序的崩溃。

简单Access Violation的异常派发,Vista/Longhorn Server相关推荐

  1. CFileDialog 在使用sdk 后出现异常 Access violation

    /*************************************************************************************************** ...

  2. 关于瞎报Access violation writing location异常的瞎解决方法

    文章目录 @[toc] 问题描述 解决办法 问题描述 最近在用OpenCV解决一些CV问题.嗯,VS2017,各位看官不要笑,我也想用Linux,没办法,VS对于菜鸡来说是真的好用,虽然配环境确实蛋疼 ...

  3. 如何捕获access violation异常

    文章目录 access violation的由来 access violation的实例 Win32 exception SEH异常与C++标准异常 捕获方法 1.access violation的由 ...

  4. 智能安全实验室-全能优化(Guardio)错误解决(1):“出现异常:EXCEPTION_ACCESS_VIOLATION=Access Violation”...

    如果您在使用智能安全实验室-全能优化(Guardio)的过程中遇到类似以下的错误: 过程:2090043535:时间:2006-2-9 10:31:57:异常:EXCEPTION_ACCESS_VIO ...

  5. access violation at address 异常

    项目场景: access violation at address 异常 问题描述: 最近打开navicat客户端 会出现access violation at address-网上百度了下是内存越界 ...

  6. 【CAD异常】未处理的异常C0000005(Access Violation Reading 0x0010),地址:5C6B5587h

    win 10环境,CAD2007,添加.arx扩展的时候,报错,错误信息:未处理的异常C0000005(Access Violation Reading 0x0010),地址:5C6B5587h. 解 ...

  7. Access violation reading location 0xccccccc0运行异常的解决方法

    转自:http://blog.csdn.net/michealmeng555/article/details/6452697 编译过运行时出现如下错误 Access violation reading ...

  8. access violation at address 解决之法【转】

    右击"我的电脑".单击"属性". 在"系统属性"中单击"高级". 在"性能"中单击"设置& ...

  9. Forrtl: severe(157): Program Exception - access violation

    这是在Fortran中经常碰到的错误,access violation一般是访问到了不能访问的内存. 个人碰到几种情况: Array-out-of-bounds error:数组越界 Stack ov ...

最新文章

  1. Latex快速入门, Windows 安装使用编译技巧归纳
  2. python3 requirements使用方法 ~= >= <
  3. 版本控制介绍以及常用的版本控制工具
  4. facebook 分享页面_Facebook个人资料,页面和组之间有什么区别?
  5. 仿短视频竖屏播放源码
  6. python教程-做个淘宝双十一满减攻略
  7. 如何查找识别苹果无线鼠标/无线键盘/触控板的设备序列号
  8. 杨辉三角c语言if 编程,杨辉三角_用c语言怎么编程
  9. python画三色柱状图_python画手绘图
  10. 历史记录具体时间linux,查看命令历史记录及其操作时间
  11. 微信服务号添加小程序
  12. 网站是否进行过SEO网站优化?主要就看这三点!
  13. 【原创开源应用第2期】基于RL-USB和RL-FlashFS的完整NAND解决方案,稳定好用,可放心用于产品批量
  14. Ceph监控部署之inkscopeCalamari(v10.2.11)
  15. WIN32 opengl缩放、旋转、移动图形
  16. 《Mysql数据库》
  17. 高效通过,PMI-ACP 备考知识突击(九阴真经版)
  18. ubuntu18.04配置静态ip
  19. C#源码QQ空间自动点赞神器,无需密码直接点头像登录,可加自动功能评论转发等。
  20. python之pygal学习

热门文章

  1. 关于.NET编译的目标平台(AnyCPU,x86,x64) (转)
  2. ASP.NET状态管理之三(隐藏域HiddenField)
  3. mysql 5.7 解决 set global slow_query_log=on;报错
  4. PHP程序员上相亲节目,结果遭女嘉宾瞬间全灭灯
  5. 最大输入hdu 2534 规律水题 求任意个a,b的和 不能表示的最大的数
  6. 传说中的裸奔节--认识及体验CSS
  7. 基于WebForm的Front Controller模式框架
  8. 第一次搭建vue项目--安装vue-cli、初始化项目
  9. 自学习 与 无监督特征学习
  10. HTML5新特性---Form表单前台通过正则表达式自动验证邮箱