zoukankan      html  css  js  c++  java
  • .net core 处理异常的精髓部分

    .net core 里面处理异常无论是在linux 或者是widnows都有一个异常入口函数processclrexception()

    core里面的异常分为用户异常和硬件异常,前者是代码里面引发的异常,后面是CPU寄存器硬件等引发的异常

    两者处理不同在于VEH扩展,当硬件异常的时候,会调用注册的VEH处理异常。而后进入processclrexception,用户异常则省略了VEH部分直接进入

    当引发异常的时候,Jithelpers类会调用IL_throw进行处理。然后调用windows api raiseexception抛出异常,通过Windows处理机制进入异常入口函数

    这个函数在 linux和windwos上通用,捕捉到异常之后,需要获取异常函数和调用来源,可以通过函数栈来递推循环处理得到来源。当获取到调用的

    来源之后,就可以获取core clr 的异常处理,在 .net 里面每个函数都有一个异常处理表。获取到之后,可以枚举异常处理表一次调用 try ,catch ,finally

    快的数据。以便处理异常。

    IL_Throw 代码如下,主要是引入异常类的对象,然后RaiseTheExceptionInternalOnly函数,在这个函数里了调用了RaiseException(code, flags, argCount, args),

    抛出异常代码,被processclrexception捕捉到。然后流程进入processclrexception。

    IL_Throw代码如下:

     1 HCIMPL1(void, IL_Throw, Object* obj)
     2 {
     3 FCALL_CONTRACT;
     4 
     5 // This "violation" isn't a really a violation. 
     6 // We are calling a assembly helper that can't have an SO Tolerance contract
     7 CONTRACT_VIOLATION(SOToleranceViolation);
     8 /* Make no assumptions about the current machine state */
     9 ResetCurrentContext();
    10 
    11 FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC
    12 
    13 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame
    14 
    15 OBJECTREF oref = ObjectToOBJECTREF(obj);
    16 
    17 #if defined(_DEBUG) && defined(_TARGET_X86_)
    18 __helperframe.InsureInit(false, NULL);
    19 g_ExceptionEIP = (LPVOID)__helperframe.GetReturnAddress();
    20 #endif // defined(_DEBUG) && defined(_TARGET_X86_)
    21 
    22 
    23 if (oref == 0)
    24 COMPlusThrow(kNullReferenceException);
    25 else
    26 if (!IsException(oref->GetMethodTable()))
    27 {
    28 GCPROTECT_BEGIN(oref);
    29 
    30 WrapNonCompliantException(&oref);
    31 
    32 GCPROTECT_END();
    33 }
    34 else
    35 { // We know that the object derives from System.Exception
    36 if (g_CLRPolicyRequested &&
    37 oref->GetMethodTable() == g_pOutOfMemoryExceptionClass)
    38 {
    39 EEPolicy::HandleOutOfMemory();
    40 }
    41 
    42 // If the flag indicating ForeignExceptionRaise has been set,
    43 // then do not clear the "_stackTrace" field of the exception object.
    44 if (GetThread()->GetExceptionState()->IsRaisingForeignException())
    45 {
    46 ((EXCEPTIONREF)oref)->SetStackTraceString(NULL);
    47 }
    48 else
    49 {
    50 ((EXCEPTIONREF)oref)->ClearStackTracePreservingRemoteStackTrace();
    51 }
    52 }
    53 
    54 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
    55 if (!g_pConfig->LegacyCorruptedStateExceptionsPolicy())
    56 {
    57 // Within the VM, we could have thrown and caught a managed exception. This is done by
    58 // RaiseTheException that will flag that exception's corruption severity to be used
    59 // incase it leaks out to managed code.
    60 //
    61 // If it does not leak out, but ends up calling into managed code that throws,
    62 // we will come here. In such a case, simply reset the corruption-severity
    63 // since we want the exception being thrown to have its correct severity set
    64 // when CLR's managed code exception handler sets it.
    65 
    66 ThreadExceptionState *pExState = GetThread()->GetExceptionState();
    67 pExState->SetLastActiveExceptionCorruptionSeverity(NotSet);
    68 }
    69 #endif // FEATURE_CORRUPTING_EXCEPTIONS
    70 
    71 //这个函数进入,调用抛出异常
    72 
    73 RaiseTheExceptionInternalOnly(oref, FALSE);
    74 
    75 HELPER_METHOD_FRAME_END();
    76 }

    .Net Core C++ 异常模型

     1 #define WIN32_LEAN_AND_MEAN
     2 
     3 #include <windows.h>
     4 #include <stdio.h>
     5 DWORD scratch;
     6 EXCEPTION_DISPOSITION
     7 __cdecl
     8 processclrexception(struct _EXCEPTION_RECORD* ExceptionRecord,
     9 void* EstablisherFrame,
    10 struct _CONTEXT* ContextRecord,
    11 void* DispatcherContext)
    12 {
    13 unsigned i;
    14 // 指明是我们让流程转到我们的异常处理程序的
    15 printf("Hello from an exception handler
    ");
    16 // 改变CONTEXT结构中EAX的值,以便它指向可以成功进写操作的位置
    17 ContextRecord->Eax = (DWORD)&scratch;
    18 // 告诉操作系统重新执行出错的指令
    19 return ExceptionContinueExecution;
    20 }
    21 int main()
    22 {
    23 DWORD handler = (DWORD)processclrexception
    24 __asm
    25 {
    26 // 创建EXCEPTION_REGISTRATION结构:
    27 push handler // handler函数的地址
    28 push FS : [0] // 前一个handler函数的地址
    29 mov FS : [0] , ESP // 安装新的EXECEPTION_REGISTRATION结构
    30 }
    31 RaiseException(EXCEPTION_ACCESS_VIOLATION
    32 , EXCEPTION_NONCONTINUABLE, 0, NULL);
    33 //__asm
    34 //{
    35 // mov eax, 0 // 将EAX清零
    36 // mov[eax], 1 // 写EAX指向的内存从而故意引发一个错误
    37 //}
    38 printf("After writing!
    ");
    39 __asm
    40 {
    41 // 移去我们的EXECEPTION_REGISTRATION结构
    42 mov eax, [ESP] // 获取前一个结构
    43 mov FS : [0] , EAX // 安装前一个结构
    44 add esp, 8 // 将我们的EXECEPTION_REGISTRATION弹出堆栈
    45 }
    46 return 0;
    47 
    48 }

    下面是ProcessCLRException,这个函数非常长,长达几千行,只贴出部分有用的

     1 ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord
     2 WIN64_ARG(IN ULONG64 MemoryStackFp)
     3 NOT_WIN64_ARG(IN ULONG MemoryStackFp),
     4 IN OUT PCONTEXT pContextRecord,
     5 IN OUT PDISPATCHER_CONTEXT pDispatcherContext
     6 )
     7 {
     8 
     9 DWORD   dwLastError     = GetLastError();//获取到当前的执行结果
    10 
    11 ExceptionTracker* pTracker = ExceptionTracker::GetOrCreateTracker( // 这个函数里面会实例化一个异常的托管类,比如ExceptionArgument类等。
    12 pDispatcherContext->ControlPc,
    13 sf,
    14 pExceptionRecord,
    15 pContextRecord,
    16 bAsynchronousThreadStop,
    17 !(dwExceptionFlags & EXCEPTION_UNWINDING),
    18 &STState);
    19 
    20 status = pTracker->ProcessOSExceptionNotification( // 这个函数会调用 .net core里面的 异常的try块的代码
    21 pExceptionRecord,
    22 pContextRecord,
    23 pDispatcherContext,
    24 dwExceptionFlags,
    25 sf,
    26 pThread,
    27 STState
    28 #ifdef USE_PER_FRAME_PINVOKE_INIT
    29 , (PVOID)pICFSetAsLimitFrame
    30 #endif // USE_PER_FRAME_PINVOKE_INIT
    31 );
    32 
    33 ClrUnwindEx(pExceptionRecord,// 这个函数调用了 windows api RtlUnwindEx 。RtlUnwindEx第二次调用ExceptionHandler,执行展开操作,清理资源等
    34 (UINT_PTR)pThread,
    35 INVALID_RESUME_ADDRESS,
    36 pDispatcherContext->EstablisherFrame);
    37 
    38 // .net core里面的异常try 块被执行了,如果有finally ,在这里会被执行。调用了windwos api RtlRestoreContext(pContextRecord, pExceptionRecord);执行finally 块
    39 
    40 ExceptionTracker::ResumeExecution(pContextRecord,pExceptionRecord);
    41 
    42                                               NULL
    43 
    44                                               );
    45 
    46 }

    以上就是大致的.net core 异常处理流程。有疑问可以一起交流 QQ群:676817308

  • 相关阅读:
    leetcode33. Search in Rotated Sorted Array
    pycharm 设置sublime text3 monokai主题
    django class Meta
    leetcode30, Substring With Concatenation Of All Words
    Sublime text3修改tab键为缩进为四个空格,
    sublime text3 python打开图像的问题
    安装上imesupport输入法依然不跟随的解决办法,
    sublime text3 的插件冲突弃用问题,
    sublime text3 BracketHighlighter括号匹配的设置
    windows 下wget的使用
  • 原文地址:https://www.cnblogs.com/tangyanzhi1111/p/12830571.html
Copyright © 2011-2022 走看看