《异常处理得与失.ppt》由会员分享,可在线阅读,更多相关《异常处理得与失.ppt(40页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、异常处理得与失张银奎摘要异常机制为处理软件执行过程中的“意外”情况提供了一种重要手段,但它是否可以取代传统的错误处理方法呢?C+语言规范定义了异常处理,但没有规定如何来实现。操作系统是如何分发异常的,异常处理的开销有多大呢?本演讲以Windows操作系统和Visual C+编译器为例层层剥茧,由浅入深的回答了以上问题,比较深入的探讨了如何在软件开发中正确的使用异常处理机制,并以实验数据和演示分析了滥用异常处理会导致的严重问题。在我公司的咨询业务中C+异常处理一直是最令软件开发公司迷惑的一个问题。John RobbinsThe popular belief is that exceptions
2、provide a straightforward mechanism for adding reliable error handling to our programs.On the contrary,I see exceptions as a mechanism that may cause more ills than it cures.EXCEPTION HANDLING:A FALSE SENSE OF SECURITY by Tom Cargill 目录异常过程未处理的异常异常处理的开销观点和建议异常来源CPU检测到的执行错误除0,GP,无效指令程序产生Int 3,throw E
3、Machine Check Exceptions总线错误,ECC错误,Cache错误异常来源分类C+异常处理(EH)C+标准,关键字:try,catch,throw结构化异常处理(SEH)Structured Exception HandlingWindows操作系统的异常机制具体实现依赖于编译器:_try,_except,_finally向量式异常处理(VEH)Vectored Exception Handling Windows XP引入,对SEH的补充异常处理五阶段1.发生2.表征3.捕捉分发4.处理lEXCEPTION_CONTINUE_SEARCH(0)lEXCEPTION_EXEC
4、UTE_HANDLER(1)lEXCEPTION_CONTINUE_EXECUTION(-1)5.善后l恢复(resuming exception)l终止(terminating exception)异常处理五阶段-SEHint filter(void)/*Stage 4*/int main(void)_try if(some_error)/*Stage 1*/RaiseException(.);/*Stage 2*/*Stage 5 of resuming exception*/_except(filter()/*Stage 3*/*Stage 5 of terminating except
5、ion*/return 0;异常处理五阶段-EHint main(void)try if(some_error)/*Stage 1*/thow E();/*Stage 2*/carch(E&)/*Stage 3*/*Stage 4*/*Stage 5*/return 0;主动抛出异常E e=E();_CxxThrowException(&e,E_EXCPT_INFO_ADDR);throw E();CxxThrowException#define CXX_FRAME_MAGIC 0 x19930520#define CXX_EXCEPTION 0 xe06d7363VOIDNTAPI_CxxT
6、hrowException(IN PVOID Object,IN PVOID CxxExceptionType )ULONG_PTR ExceptionInformation3;ExceptionInformation0=CXX_FRAME_MAGIC;ExceptionInformation1=(ULONG_PTR)Object;ExceptionInformation2=(ULONG_PTR)CxxExceptionType;RaiseException(CXX_EXCEPTION,EXCEPTION_NONCONTINUABLE,3,ExceptionInformation );Rais
7、eExceptionVOIDNTAPIRaiseException(IN ULONG ExceptionCode,IN ULONG ExceptionFlags,IN ULONG NumberParameters,IN CONST ULONG_PTR *ExceptionInformation )EXCEPTION_RECORD ExceptionRecord=ExceptionCode,ExceptionFlags&EXCEPTION_NONCONTINUABLE,NULL,RaiseException,/指向本函数的指针 NumberParameters EXCEPTION_MAXIMUM
8、_PARAMETERS?EXCEPTION_MAXIMUM_PARAMETERS:NumberParameters ;RtlCopyMemory(ExceptionRecord.ExceptionInformation,ExceptionInformation,ExceptionRecord.NumberParameters*sizeof(ULONG_PTR);RtlRaiseException(&ExceptionRecord);ExceptionFlags0可恢复继续执行的异常 EXCEPTION_NONCONTINUABLE(1)不可恢复继续执行的异常,如果企图恢复继续执行,则会导致EX
9、CEPTION_NONCONTINUABLE_EXCEPTION异常实例Args to Child 0012fe28 0012fb44 00000001 ntdll!NtRaiseException+0 xa0012fe28 004251b8 e06d7363 ntdll!RtlRaiseException+0 x93e06d7363 00000001 00000003 kernel32!RaiseException+0 x510012ff18 00426680 0012ff80 vcexp!_CxxThrowException+0 x39直接调用RaiseExceptionChildEBP
10、RetAddr Args to Child 0012fbac 77f5bf94 77f96673 0012fea8 0012fbc4 SharedUserData!SystemCallStub+0 x2(FPO:0,0,0)0012fbb0 77f96673 0012fea8 0012fbc4 00000001 ntdll!NtRaiseException+0 xc(FPO:3,0,0)0012fe98 77e738b2 0012fea8 0012ff10 e0000001 ntdll!RtlRaiseException+0 x930012fef8 004010d5 e0000001 0000
11、0000 00000000 kernel32!RaiseException+0 x51(FPO:Non-Fpo)0012ff80 004016d9 00000001 003715a0 00371618 se!main+0 xc5(CONV:cdecl)C:digdbgexceptionadvexpsese.cpp 340012ffc0 77e8141a 00000000 00000000 7ffdf000 se!mainCRTStartup+0 xe9(CONV:cdecl)crt0.c 2060012fff0 00000000 004015f0 00000000 78746341 kerne
12、l32!BaseProcessStart+0 x23(FPO:Non-Fpo)进入内核ZwRaiseExceptionKiDispatchExceptionRaiseExceptionRtlRaiseExceptionNtRaiseExceptionZwRaiseExceptionNTSYSAPINTSTATUSNTAPIZwRaiseException(IN PEXCEPTION_RECORD ExceptionRecord,IN PCONTEXT Context,IN BOOLEAN SearchFrames);KiDispatchExceptionWindows NT/2000 Nati
13、ve API Reference by Gary Nebbett if(SearchFrames)if(PsGetCurrentProcess()-DebugPort=0|KdIsThisAKdTrap(Tf,&Context)if(KiDebugRoutine&KiDebugRoutine(Tf,Reserved,Er,&Context,PreviousMode,FirstChance)!=0)break;if(DbgkForwardException(Tf,DebugEvent,FirstChance)!=0)return;if(valid_user_mode_stack_with_eno
14、ugh_space)Tf-Eip=KeUserExceptionDispatcher;return;if(DbgkForwardException(Tf,DebugEvent,LastChance)!=0)return;if(DbgkForwardException(Tf,ExceptionEvent,LastChance)!=0)return;ZwTerminateThread(NtCurrentThread(),Er-ExceptionCode);返回用户态ntdll!RtlpUnlinkHandler+0 xdvcexp!_UnwindNestedFrames+0 x2cvcexp!_F
15、rameUnwindToState+0 x16dvcexp!_InternalCxxFrameHandler+0 x319vcexp!_InternalCxxFrameHandler+0 xe3vcexp!_CxxFrameHandler+0 x2cntdll!ExecuteHandler2+0 x26ntdll!ExecuteHandler+0 x24ntdll!KiUserExceptionDispatcher+0 xekernel32!RaiseException+0 x51vcexp!_CxxThrowException+0 x39vcexp!vc_throw(void)+0 x4c
16、C:DIGDBGEXCEPTIONadvexpvcexp.cpp 27vcexp!main(void)+0 x1d C:DIGDBGEXCEPTIONadvexpvcexp.cpp 44vcexp!mainCRTStartup(void)+0 xe9 crt0.c 206kernel32!BaseProcessStart+0 x23ExecuteHandler2ntdll!ExecuteHandler2:77fb1708 55 push ebp77fb1709 8bec mov ebp,esp77fb170b ff750c push dword ptr ebp+0 xc77fb170e 52
17、push edx77fb170f 64ff3500000000 push dword ptr fs:0000000077fb1716 64892500000000 mov fs:00000000,esp77fb171d ff7514 push dword ptr ebp+0 x1477fb1720 ff7510 push dword ptr ebp+0 x1077fb1723 ff750c push dword ptr ebp+0 xc77fb1726 ff7508 push dword ptr ebp+0 x877fb1729 8b4d18 mov ecx,ebp+0 x1877fb172c
18、 ffd1 call ecx se!_except_handler3(004014d4)77fb172e 648b2500000000 mov esp,fs:0000000077fb1735 648f0500000000 pop fs:0000000077fb173c 8be5 mov esp,ebp77fb173e 5d pop ebp77fb173f c21400 ret 0 x1477fb1742 8b4c2404 mov ecx,esp+0 x477fb1746 f7410406000000 test dword ptr ecx+0 x4,0 x677fb174d b801000000
19、 mov eax,0 x177fb1752 7512 jnz ntdll!ExecuteHandler2+0 x5e(77fb1766)77fb1754 8b4c2408 mov ecx,esp+0 x877fb1758 8b542410 mov edx,esp+0 x1077fb1783 8b4108 mov eax,ecx+0 x877fb1786 8902 mov edx,eax77fb1788 b803000000 mov eax,0 x377fb178d c21000 ret 0 x10空间开销 struct tryblock DWORDstart_id;DWORDend_id;DW
20、ORDu1;DWORDcatchblock_count;catchblock*pcatchblock_table;enum VAL_OR_REF BY_VALUE=0,BY_REFERENCE=8;struct catchblock DWORD val_or_ref;/Whether the exception is passed /by val or by reference type_info*ti;int offset;/offset from stack frame pointer /(EBP)where exception should be /copied.DWORD catchb
21、lock_addr;struct funcinfo DWORD sig;DWORD unwind_count;/number of entries in unwindtable unwind *punwindtable;DWORD tryblock_count;/number of entries in tryblocktable tryblock*ptryblock_table;时间开销Happy PathUnhappy PathTraditional Method20 ms21 msExceptional method60 ms3294 ms未处理的异常 Windows XP未处理的异常
22、Win2K Server未处理的异常-BSODBlue Screen of Death内核模式下操作系统强制STOPKebugCheckEx()反对意见-Tom CargillEXCEPTION HANDLING:A FALSE SENSE OF SECURITYFirst appeared in C+Report,Volume 6,Number 9,November-December 1994 While entirely in favor of robust error handling,I have serious doubts that exceptions will engender
23、 software that is any more robust than that achieved by other means.I am concerned that exceptions will lull programmers into a false sense of security,believing that their code is handling errors when in reality the exceptions are actually compounding errors and hindering the software.反对意见 违反OO原则Is
24、sues with Exception Handling in Object-Oriented Systems by Robert Miller and Anand Tripathi in Computer Science Department of University of MinnesotaAbstraction:generalization of operations and composition construction may involve changing of abstraction levels and dealing with partial states.Encaps
25、ulation:the exception context may leak information that allows implementation details or private data of the signaler to be revealed or accessed.Modularity:design evolution(function and implementation)maybe inhibited by exception conformance.Inheritance:the inheritance anomaly can occur when a langu
26、age does not support exception handling augmentation in a modular way.反对意见-Joel Spolsky I consider exceptions to be no better than gotos,considered harmful since the 1960s,in that they create an abrupt jump from one point of code to another.In fact they are significantly worse than gotos:They are in
27、visible in the source code.They create too many possible exit points for a function.John Robbins的意见缺点1:不具有纯语言特征缺点2:容易被滥用“许多人抛出的论点是,使用C+异常的最好理由是程序员从来不检查函数的返回值。这样的论点不仅是完全不对的,而且是糟糕的编程方法的借口。”“本机应用程序中导致性能下降的最大根源是不必要的异常。”John Robbins的意见绝对、一定、永远不要使用catch()“catch()结构为我的银行帐号做过很多贡献了”没有办法知道为何到此!不仅捕获C+异常,还捕获SHE
28、异常,难以分析。关键问题不可预知的出口影响性能,branch prediction失败破坏结构化和封装原则性能上的副作用难以在软件工程中实施何时何处 可以/不可 抛出/捕捉 Joel的建议Never throw an exception of my own.Always catch any possible exception that might be thrown by a library Im using on the same line as it is thrown and deal with it immediately.监视异常VEHPVOID AddVectoredExcept
29、ionHandler(ULONG FirstHandler,PVECTORED_EXCEPTION_HANDLER VectoredHandler);LONG WINAPI VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo);VEH的优点不绑定任何函数和栈代码显式加入,不像EH有很多隐式处理进程内的全局性早于其它机制得到处理权结论模块内和内部模块之间不要用抛出异常代替错误返回;设置全局性的异常预处理和未处理异常补救措施;定义完善的错误处理政策和机制错误日志错误代码格式参考文献/资源A Crash Course on the Depths of Win32 Structured Exception Handling by Matt Pietrek Handling Exceptions in C and C+by Robert Schmidthttp:/ Q&A