我看到了一些关于Rotor(和CLR)中使用的异常处理机制的问题。下面是关于Rotor异常处理的另一个注意事项列表。目的是帮助Rotor开发人员调试和理解CLR中的异常。

异常生成和抛出

此步骤在很大程度上取决于异常的类型以及从何处引发异常:

jitted代码中的软件异常---使用C#中throw new MyException(…)引发的异常

  • 异常对象的创建方式与任何其他托管对象的创建方式相同
  • vm\jitiface.cpp中调用JIT_Throw
  • HelperFrame被推送以标记从jitted到EE代码的转换。这是可靠的stack walk工作所必需的——安全性和垃圾收集是可靠stackwalk的主要用户。
  • vm\excep.cpp中调用了RaiseTheException
  • 异常对象存储在当前线程对象中
  • EXCEPTION_COMPLUS异常是使用Win32的RaiseException API引发的

执行引擎代码中的软件异常---在clr\src\vm目录中使用COMPlusThrow(…)引发异常

  • 如果尚未提供给调用,则异常对象的创建方式与任何其他托管对象的创建方式相同
  • vm\excep.cpp:RaiseTheException被调用,故事的其余部分与第一个案例相同。
  • 注意:不需要推送任何转换框架
  • 注意:在托管异常堆栈跟踪中不包含C++ stacttrace。

jitted代码中的硬件异常-如访问空对象、除以零等。

  • 将调用jitted代码的异常处理程序。大多数时候它是vm\i386\excepx86.cpp:COMPlusFrameHandler。
  • 异常被标识为直接来自vm\i386\excepx86.cpp:CPFH_HandleManagedFault中的jitted代码。
  • 推送FaultingExceptionFrame以标记从jitted到EE代码的特殊转换。
  • 使用vm\i386\excepx86.cpp:LinkFrameAndRow和关联的asm帮助程序重新引发异常。
    对于Win32/i386 SEH,通过将IP修改为指向NakedThrowHelper的异常过滤器返回EXCEPTION_CONTINUE_EXECUTION来完成重新触发。
    对于PAL_PORTABLE_SEH,通过简单调用LaunchNakedThrowHelper来完成重新触发。
  • 第二次在异常过滤器中,为硬件异常创建正确类型的异常对象。硬件异常到BCL异常类型的映射在vm\excep.cpp:MapWin32FaultToCOMPlusException中完成。
  • 注意:硬件异常重试是一个实现细节,它应该允许可继续的异常(异常继续执行)无缝工作。CLI目前不支持可延续的异常,但将来可能会有所改变。此外,可能存在一些互操作场景,其中异常继续执行非常重要。
  • 注意:对于PAL_PORTABLE_SEH,硬件异常的重新触发是不同的,因为PAL不支持异常继续执行。稍后为调试器支持添加了异常继续执行。

执行引擎代码中的硬件异常

执行引擎代码中的硬件异常通常不应该发生。如果他们这样做了,通常意味着事情真的出了问题,需要大量的运气才能从这种情况中恢复过来。不过,这条规则有几个例外:

  • 写入屏障帮助程序(vm\i386\jithelp.asm:JIT_write barrier and friends)中的访问冲突被转换为调用程序中的访问冲突。转换在vm\i386\excepx86.cpp:CPFH_AdjustContextForWriteBarrier中完成。这允许JIT在调用写回载波时优化空检查。FJIT当前不使用此功能。
  • 尽管存在一些防止堆栈溢出异常(vm\stackprobe.h)的屏蔽,但它们可能发生在执行引擎代码中,这通常非常糟糕。这是为.NET v1设计的,CLR团队正在为Whidbey开发更好的解决方案。便携式堆栈溢出处理不在转子-我们只是死时堆栈溢出发生。可移植堆栈溢出处理的设计和实现留给读者练习
  • 元数据代码用于访问监视(#define ZAP_MONITOR),以允许按配置文件引导的元数据布局优化。检测是通过使所有元数据访问A/V、记录它们并通过异常继续执行从它们恢复来完成的。(是的,这个解决方案的性能很差。)元数据工具不是作为Rotor的一部分提供的,但是必须记住它以避免代码损坏。

FCalls中的软件异常--使用FCThrow(…)及其类似调用引发的异常

Fcall闻起来像jitted代码,但实际上不是,因此Fcall中的异常处理是特殊的。

  • 如果未推送helper框架,则使用FCThrow helpers从fcall抛出异常。(如果推送helperframe,则它是使用complushrow在执行引擎代码中抛出软件异常的简单方法)
  • FCThrow helper使用特殊帧ATTR_CAPTURE_DEPTH_2推动辅助帧。因此,只能直接从FCALL调用FCThrow。不能从从FCALL调用的函数调用它。
  • 一旦helper框架被推送,complushrow就会像执行引擎代码中的任何其他软件异常一样实际抛出异常。
  • 注意:FCThrow只是HELPER_METHOD_FRAME_BEGIN(…);complusthrow(…);HELPER_METHOD_FRAME_END()的快捷方式。如果您看到了长代码模式,那么在尝试使用FCThrow对其进行优化时要小心—它可能是有原因的。fcall依赖于一个非常脆弱的x86解释器。这个翻译有时需要帮助.

可以看到,所有异常都转换为一个看起来像常规托管异常的统一案例。从托管代码引发的每个异常(无论是硬件异常还是软件异常)都会下放到Win32 RaiseException层。这样做是为了保持一致性。它被认为可以简化互操作性的实现。

处理异常

异常的处理遵循两次机会的Win32模型。
第一次,stackwalker为堆栈上的每个方法调用回调。一旦某个过滤器返回它处理异常,异常展开的第二次传递就开始了。
第二次,堆栈已展开。展开代码的结构在本机Win32 i386异常处理和PAL可移植异常处理之间有所不同。

异常和垃圾收集器

请注意,对RaiseException的调用是由EE代码发出的,并且此代码以协作模式运行。因此,在异常分派期间不会阻止垃圾收集。

异常和帧

帧的链接列表(Frame-vm\frames.h类的后代)与每个线程对象关联。这些是可靠的堆栈遍历基础设施的关键部分。执行引擎代码正在使用一种特殊的机制来释放异常时的链。COMPLUS-TRY/COMPLUS-CATCH宏(vm\exceptmacros.h)通过在异常时调用unwind frame chain(vm\excepp.cpp)来展开帧链。此外,这些宏还释放嵌套的异常信息(vm\excep.cpp:UnwindExInfo)并还原GC模式,这非常方便。
请注意,UnwindFrameChain正在访问已展开的堆栈空间。这是可行的,但它取决于堆栈展开的微妙的低级实现细节。由于Win32/i386 SEH和PAL_PORTABLE_SEH之间堆栈展开的低级实现细节不同,因此COMPLUS_TRY/COMPLUS_CATCH宏对于这两个宏是不同的。它还解释了为什么有必要在执行引擎中使用COMPLUS-TRY/COMPLUS-catch捕获异常,而不使用常规的PAL-TRY/PAL-catch除外。
CLR开发人员没有选择通过为类框架创建C++析构函数来解开帧链,这将是一个非常简单的解决方案。这可能是一个纯粹的历史遗留物;它们可能有一些性能童话;或者对象析构函数与结构化异常处理的混合,而MSC不支持的结构异常处理会在编写代码时造成太多的不适。

异常与C++对象展开

在异常解除时,PAL_PORTABLE_SEH 不调用堆栈上的对象的C++析构函数。这是可以的,因为执行引擎代码似乎没有利用当前的C++特性。嗯,我们还没有找到它依赖于被调用的C++的地方。这可能会因Whidbey而改变

异常和安全

由于存在安全隐患,因此从异常处理中正确执行堆栈遍历非常重要。对于过滤器来说,这是特别棘手的,因为在调用过滤器时,真正的堆栈是不展开的。在抛出异常到最后调用异常之间,可以调用来自堆栈上源代码的任意用户代码。

Rotor

Rotor里的异常处理的更多相关文章

  1. [R]R语言里的异常处理与错误控制

    之前一直只是在写小程序脚本工具,几乎不会对异常和错误进行控制和处理. 随着脚本结构和逻辑更复杂,脚本输出结果的准确性验证困难,同时已发布脚本的维护也变得困难.所以也开始考虑引入异常处理和测试工具的事情 ...

  2. Visual C++ 里的异常处理

    微软Visual C++是Win32最广泛使用的编译器,因此Win32反向器对其内部工作非常熟悉.能够识别编译器生成的粘合代码有助于快速集中于程序员编写的实际代码.它还有助于恢复程序的高级结构.我将集 ...

  3. int main(int argc, char * argv[]) 里的异常处理

    #import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { ...

  4. java异常处理的设计

    有一句这样话:一个衡量Java设计师水平和开发团队纪律性的好方法就是读读他们应用程序里的异常处理代码. 本文主要讨论开发Java程序时,如何设计异常处理的代码,如何时抛异常,捕获到了怎么处理,而不是讲 ...

  5. Struts2、Spring MVC4 框架下的ajax统一异常处理

    本文算是struts2 异常处理3板斧.spring mvc4:异常处理 后续篇章,普通页面出错后可以跳到统一的错误处理页面,但是ajax就不行了,ajax的本意就是不让当前页面发生跳转,仅局部刷新, ...

  6. [转贴]从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介

    一.C语言错误处理方法 1.返回值(if … else语句判断错误) 2.errno(linux 系统调用) 3.goto语句(函数内局部跳转) 4.setjmp.longjmp(Do not use ...

  7. 从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介

    一.C语言错误处理方法 1.返回值(if … else语句判断错误) 2.errno(linux 系统调用) 3.goto语句(函数内局部跳转) 4.setjmp.longjmp(Do not use ...

  8. day 21 - 1 包,异常处理

    创建目录代码 1. 无论是 import 形式还是 from...import 形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法2. 包是目录级的(文 ...

  9. day21:包和异常处理

    1,复习 # 序列化模块 # json # dumps # loads # dump 和文件有关 # load load不能load多次 # pickle # 方法和json的一样 # dump和lo ...

随机推荐

  1. hystrixDashboard(服务监控)

    1.新建项目 microservicecloud-consumer-hystrix-dashboard 2.yml文件 server: port: 9001 3.在pom.xml文件增加如下内容 &l ...

  2. 【C/C++开发】C++静态库与动态库以及在Linux和Windows上的创建使用

    原文出处: 吴秦的博客    这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学 ...

  3. BCompare注册文件+密钥被撤销解决方案

    注册码: rssAPVg2OpBjDVo3E0DhGWrjPIq0hsTSuNz13wTuzVHfb2mRgO9bZKn9Bl42D5YEyMSYPXsxzcb08dqbRlbzWNJzJXE6YVa ...

  4. ping不通服务器的解决方法

    参考腾讯云的解决办法: https://cloud.tencent.com/document/product/213/14639#CheckOSSetting 我的服务器是aws的, 解决方法大同小异 ...

  5. 【maven】pom.xml的exclusions排除依赖传递

    在引用两个有冲突的依赖时,就需要把其中一个的依赖中某个依赖排除掉 exclusions 例如: <dependency> <groupId>org.activiti</g ...

  6. Clean Code 笔记 之 第二章

    你是否真正的会命名 前言 这是我第二次看这本书了(Clean Code)的时候,第一次看的时候是,看到某世界五百强在他们的代码中我竟然看不到一句注释,现在我还记得当时的情景,当我Download 下第 ...

  7. CentOS升级Python2.6到Python2.7并安装pip[转载]

    貌似CentOS 6.X系统默认安装的Python都是2.6版本的?平时使用以及很多的库都是要求用到2.7版本或以上,所以新系统要做的第一件事必不可少就是升级Python啦!在这里做个简单的升级操作记 ...

  8. 集合类源码(三)Collection之List(CopyOnWriteArrayList, Stack)

    CopyOnWriteArrayList 功能 全名 public class CopyOnWriteArrayList<E> implements List<E>, Rand ...

  9. Spring Boot Swagger2自动生成接口文档

    一.简介 在当下这个前后端分离的技术趋势下,前端工程师过度依赖后端工程师的接口和数据,给开发带来了两大问题: 1.问题一.后端接口查看难:要怎么调用?参数怎么传递?有几个参数?参数都代表什么含义? 2 ...

  10. 一个简单 System.Threading.Tasks.Dataflow.BufferBlock 示例

    直接贴代码了: using System; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; namespace ...