• .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

  • 相关阅读:
    每天备份数据库中的表
    IE9相容問題-childNodes行為改變
    查找含有某字符的存儲過程
    弹出SQL报表的时候,出现空白的解决方法
    转:Page.ClientScript.RegisterStartupScript(me.GetType(),"script1","<script>alert('111');</script>")
    java核心技术记录之java术语
    Head First 设计模式笔记:单例模式
    多对一关系实体中,多的一方所关联的一实体的实例化问题
    ajax请求返回json数据弹出下载框的解决方法
    java核心技术记录
  • 原文地址:https://www.cnblogs.com/tangyanzhi1111/p/12830571.html
Copyright © 2020-2023  润新知