C++异常处理分析,及格式化异常处理方法

// C++异常处理分析,及格式化异常处理方法 // #include #include #include using namespace std; /*对于一个Windows平台上的C++程序来说,异常其实可以分为两种: Win32异常,也就是结构化异常(Structured Exception)以及C++异常。 无论是Win32还是C++都为我们提供了一些机制来处理未被正常捕获的异常,让我们在应用程序退出之前尽一些人事。 针对C++异常,可以使用set_unexpected,但微软并不支持它。 Win32异常(也可以捕获C++异常),可以使用SetUnhandledExceptionFilter设置一个SEH的过滤函数。*/ //C++标准,异常规格申明(指明函数可以抛出哪些异常): //void fun() throw( A,B,C,D); 这表明函数fun()可能并且只可能抛出类型(A,B,C,D)及其子类型的异常 //void fun(); 如果在函数的声明中没有包括异常的接口声明,则此函数可以抛出任何类型的异常 //void f4() throw(...) 比前面的“抛任何东西”的函数更好,因为它类似“捕获任何东西” //void fun() thow(); 不会抛出任何类型异常 //对于违反异常规格申明,C++标准规定: //当一个函数试图抛出没有列出的异常时,通过unexpected()函数调用了一个异常处理函数。这个异常处理函数的默认实现是调用terminate() 来结束程序 //unexpected()函数是标准运行库在头文件中申明的函数;它不接受参数,也不返回任何东西,实际上unexpected()函数从不返回,就象abort()和exit()一样。 void throw_unexpected_exception() throw()//指定此函数不会抛出任何类型异常 //warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow) { printf("throw unexpected exception for test/n"); throw 1;//微软没有遵循C++标准规定,它忽略了异常规格 } void my_unexpected_handler() { printf("in my unexpected handler/n"); //可以通过转换一个unexpected异常为expected异常;维持程序存活 //http://www.cnblogs.com/youyou/archive/2005/11/22/282131.html //throw 2; // 重新抛出一个程序可以处理的异常,让程序重新获得控制,得以继续运行 terminate(); } void termfunction() { printf("in my termfunction/n"); terminate();//会再次调用termfunction;程序会陷入递归死循环 } long WINAPI ExceptionFilterProc(EXCEPTION_POINTERS *lParam) { //如果处于调试状态(F5),系统只会把异常发送给调试器(VS); printf("in my ExceptionFilterProc/n"); if(lParam->ExceptionRecord->ExceptionFlags == 0) //可修复异常 return -1; else return 1; /* EXCEPTION_EXECUTE_HANDLER = 1 已经处理了异常,结束程序,这样程序将无疾而终。 EXCEPTION_CONTINUE_SEARCH = 0 不处理异常,转交系统处理,弹出常见的错误消息框。 EXCEPTION_CONTINUE_EXECUTION = -1 修复错误,从异常发生处继续执行,最理想的做法,不过非常困难。 */ return -1; } long __stdcall __CxxUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *); void HackUnhandledException() { //所有未被捕获的C++异常最终都会调用__CxxUnhandledExceptionFilter来进行处理 //http://blog.116.com.cn/?uid-31476-action-viewspace-itemid-208426 //call stack: http://blog.csdn.net/agan4014/archive/2008/03/20/2199790.aspx SetUnhandledExceptionFilter( ExceptionFilterProc ); DWORD oldProtect; VirtualProtect( __CxxUnhandledExceptionFilter, 5, PAGE_EXECUTE_READWRITE, &oldProtect ); *(char*)__CxxUnhandledExceptionFilter = '/xe9';// far jmp *(unsigned int*)( (char*)__CxxUnhandledExceptionFilter + 1 ) = (unsigned int)ExceptionFilterProc - ( (unsigned int)__CxxUnhandledExceptionFilter + 5 ); VirtualProtect( __CxxUnhandledExceptionFilter, 5, oldProtect, &oldProtect ); } void DisableSetUnhandledExceptionFilter() { //在设置自己的异常处理函数后,调用DisableSetUnhandledExceptionFilter禁止CRT设置即可。 //http://www.cppblog.com/woaidongmao/archive/2009/10/21/99129.html void *addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"), "SetUnhandledExceptionFilter"); if (addr) { unsigned char code[16]; int size = 0; //33 C0 xor eax,eax //C2 04 00 ret 4 code[size++] = 0x33; code[size++] = 0xC0; code[size++] = 0xC2; code[size++] = 0x04; code[size++] = 0x00; DWORD dwOldFlag, dwTempFlag; VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag); WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL); VirtualProtect(addr, size, dwOldFlag, &dwTempFlag); } } int main(int argc, char* argv[]) { //标准c++规定:你可以通过标准运行库的函数std::set_unexpected()来挂接自己的处理函数 //不过微软并没有对它提供支持:http://msdn.microsoft.com/en-us/library/7twc8dwy(VS.80).aspx //unexpected_handler oldHand = set_unexpected(my_unexpected_handler); //unexpected();//calls unexpected directly, which then calls the unexpected_handler. //类似的还有set_terminate,并且微软对它提供了支持 //terminate_handler oldHand = set_terminate(termfunction); //SetUnhandledExceptionFilter(ExceptionFilterProc); //据说VS2005编译,一些C++异常无法用上面的方法捕获到,原因是: /*****************************************************/ /* Make sure any filter already in place is deleted. /* SetUnhandledExceptionFilter(NULL); //强行删掉了之前注册的异常处理函数 /* UnhandledExceptionFilter(&ExceptionPointers); /*****************************************************/ //可以用一些hack的方法解决这个问题:(参考如下) /*1*///DisableSetUnhandledExceptionFilter(); /*2*///HackUnhandledException(); throw_unexpected_exception(); printf("i got end/n"); return 0; } //基于全局try/catch的异常处理的缺点: //1.各个线程间的异常是独立的,一个线程中的try/catch块并不能够捕获到它所创建的子线程中抛出的异常。 //2.调试时某个异常被全局的异常处理程序catch到导致失去出错上下文的情况。 //参考和引用: //C与C++中的异常处理:http://www.cnblogs.com/youyou/archive/2005/11/22/282131.html //c++异常处理机制示例及讲解(作者提供了一个自定义异常类):http://ticktick.blog.51cto.com/823160/191881 //VS2005中SetUnhandledExceptionFilter函数应用: http://blog.csdn.net/alicehyxx/archive/2009/07/17/4355802.aspx //程序自动生成Dump文件: http://blog.csdn.net/alicehyxx/archive/2009/07/15/4351450.aspx //Windows用户态程序高效排错 -- 异常(Exception)和通知(Debug Event): http://blog.csdn.net/agan4014/archive/2008/03/20/2199790.aspx //Structured Exception Handling: http://msdn.microsoft.com/en-us/library/ms680657(v=VS.85).aspx //Windows 系统编程初探 (四)结构化异常处理之一: http://blog.csdn.net/xlt123/archive/2005/04/18/352005.aspx //VS2005中SetUnhandledExceptionFilter函数应用: http://www.cppblog.com/woaidongmao/archive/2009/10/21/99129.html //SetUnhandledExceptionFilter: http://blog.116.com.cn/?uid-31476-action-viewspace-itemid-208426

你可能感兴趣的:(Windows,c++,exception,pointers,fun,winapi,微软)