托管异常处理构建在Windows操作系统的结构化异常处理之上,通常称为SEH。这意味着CLR了解如何在SEH和托管异常系统之间进行互操作,这是一个非常关键的点,因为SEH基于异常代码的概念,而托管异常处理则表示使用托管类型的异常。CLR相应地将SEH异常映射到托管异常,具体取决于引发SEH异常的方式和引发者。

注意:下面的讨论重点是运行在Windows操作系统上的桌面CLR。虽然讨论的目的是帮助理解这个概念,但是它使用了一些将来可能会改变的实现细节来说明。

托管代码中的同步异常(Synchronous exceptions)

当托管代码使用throw关键字引发异常时,它已经实例化了一个托管异常对象,该对象将表示引发的异常。这将传递给CLR,CLR在线程上设置一些与异常相关的状态,并调用Kernel32的RaiseException API来引发托管异常。此API的第一个参数是引发异常的SEH异常代码,CLR传递0xE0434F4D(托管异常SEH代码)。

这时,操作系统进入处理场景,开始在引发异常的线程堆栈上寻找SEH异常处理程序。CLR将其函数之一注册为OS的异常处理程序,以处理托管代码引起的异常。当它看到CLR SEH异常代码时,它知道正在引发托管异常,并继续查找线程状态以检索与异常相关的详细信息(例如,标识表示引发异常的托管异常对象)。

因此,在同步托管抛出的情况下,很容易将SEH异常映射到托管异常类型。

托管代码中的异步异常(Asynchronous exceptions)

简单地说,异步异常是在没有显式抛出的情况下引发的异常。如果执行算术操作(例如除以零异常)或使用可能导致访问冲突(AV)等异常的不安全托管代码,则在托管代码中可能会发生这种情况。异步异常的有趣之处在于,它们是使用它们唯一的SEH异常代码来表示的。例如AV用0xc000005表示,除以0(整数)用0xC0000094表示,除以0(浮点数)用0xC000008E表示,这里列出了常见的异常,异常代码值可以在WinNT.h中找到。

当在托管代码中引发此类异常时,操作系统再次开始在引发异常的线程堆栈上查找异常处理程序。当调用CLR的异常处理程序时,它知道所讨论的异常不是托管代码同步抛出的,因为异常代码不是CLR SEH异常代码。因此,它不再查找与异常相关的详细信息的线程状态,而是将SEH异常映射到一个托管异常类型。例如,除以零异常(整数和浮点)使用System.DivideByZeroException表示。

同样,当在托管代码中生成真正的AV时,它的异常代码为0xc000005。由于托管代码具有空引用的概念,因此运行时很少再进行检查来确定AV是否表示尝试使用空引用。如果是,则映射到System.NullReferenceException。否则,它将映射到System.AccessViolationException类型(在v2.0和更高版本的运行时中)。

在Native代码中引发异常

CLR查看SEH异常的另一种方式是,托管代码使用平台调用服务(简称PInvoke)等机制调用Native代码。
在下面的示例中,堆栈自上而下增长,蓝色框架表示托管代码,而红色框架表示Native代码:

假设Zoo抛出了一个未在其中处理的Native异常,则该异常将向上传播,因为OS沿着堆栈向上移动,寻找异常的潜在处理程序。在这种情况下,由于堆栈上的下一个帧是Bar,而Bar是受管理的,因此操作系统最终会调用CLR的异常处理程序。由于SEH异常来自Native代码,因此它可能有任何异常代码。例如,它可以是一个C++异常(它具有SEH 0X06D7363的异常代码),或者它可以是一个特定于应用程序的SEH异常代码。关键在于CLR不知道存在的所有SEH异常代码(并且将来会被创建)。从映射到特定托管异常类型的角度来看,只有现有的子集是有意义的。

因此,当CLR的异常处理程序看到Native异常时,它将尝试将最常见的SEH异常代码映射到它们相应的托管异常类型(如前面用一些示例解释的那样)。对于运行时未标识的任何其他SEH异常代码,它将映射到System.runtime.InteropServices.SEH exception类型。

接下来会发生什么?

  1. 当操作系统从特定SEH异常的抛出点为堆栈上的第一个托管帧调用CLR的异常处理程序(假设堆栈上没有上下文转换)时,此映射仅完成一次。
  2. 由于此映射是基于SEH异常代码完成的,因此CLR知道给定的托管异常实例是否表示真正的Native SEH异常。例如,CLR知道System.AccessViolationException实例是否表示真正的AV或是托管代码引发的常规托管异常。为什么这很重要?好吧,当CLR确定了异常的损坏严重性时,它就会这样做!

映射完成后,CLR将开始查找异常处理程序的常规异常处理过程。

CLR如何将SEH异常映射到托管异常类型的更多相关文章

  1. c# 捕获非托管异常

    在.NET 4.0之后,CLR将会区别出一些异常(都是SEH异常),将这些异常标识为破坏性异常(Corrupted State Exception).针对这些异常,CLR的catch块不会捕捉这些异常 ...

  2. Struts2拦截器之ExceptionMappingInterceptor(异常映射拦截器)

    一.异常拦截器是什么? 异常拦截器的作用是提供一个机会,可以设置在action执行过程中发生异常的时候映射到一个结果字符串而不是直接中断. 将异常整合到业务逻辑中,比如在分层系统的调用中可以从底层抛出 ...

  3. Struts2学习第四天——全局结果,动态结果及异常映射

    1.异常映射的配置 当Action方法出错时Struts会返回异常错误信息页面,这种页面方式是不友好的,可以使用try-catch捕捉异常,然后在catch块中返回对应的错误页面.这种为单个<a ...

  4. SpringBoot2.0 基础案例(03):配置系统全局异常映射处理

    一.异常分类 这里的异常分类从系统处理异常的角度看,主要分类两类:业务异常和系统异常. 1.业务异常 业务异常主要是一些可预见性异常,处理业务异常,用来提示用户的操作,提高系统的可操作性. 常见的业务 ...

  5. SimpleMappingExceptionResolver异常映射

    转自:https://blog.csdn.net/qqqqqq654/article/details/65767701 SimpleMappingException异常映射 当异常发生时,我们可以将它 ...

  6. Java框架之SpringMVC 05-拦截器-异常映射-Spring工作流程

    SpringMVC 拦截器 Spring MVC也可以使用拦截器对请求进行拦截处理,可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口中的三个方法,也可以 ...

  7. 三:SpringBoot-配置系统全局异常映射处理

    三:SpringBoot-配置系统全局异常映射处理 1.异常分类 1.1 业务异常 1.2 系统异常 2.自定义异常处理 2.1 自定义业务异常类 2.2 自定义异常描述对象 2.3 统一异常处理格式 ...

  8. springmvc——基于xml的异常映射和基于注解的异常映射

    SpringMVC提供了基于XML和基于注解两种异常映射机制.这两种异常映射不能够只使用一个,他们需要一起使用.因为有些异常是基于注解异常映射捕获不到的. 在springmvc中,一个请求如果是由&l ...

  9. CLR via C#深解笔记三 - 基元类型、引用类型和值类型 | 类型和成员基础 | 常量和字段

    编程语言的基元类型   某些数据类型如此常用,以至于许多编译器允许代码以简化的语法来操纵它们. System.Int32 a = new System.Int32();  // a = 0 a = 1 ...

随机推荐

  1. 用python编写一个搜索引擎

    完整代码如下: #!/usr/bin/env python #-*- coding: utf-8 -*- import sys import os import datetime from PyQt5 ...

  2. 深入玩转K8S之外网如何访问业务应用

    有一个问题就是现在我的业务分配在多个Pod上,那么如果我某个Pod死掉岂不是业务完蛋了,当然也会有人说Pod死掉没问题啊,K8S自身机制Deployment和Controller会动态的创建和销毁Po ...

  3. 【题解】Luogu P5337 [TJOI2019]甲苯先生的字符串

    原题传送门 我们设计一个\(26*26\)的矩阵\(A\)表示\(a~z\)和\(a~z\)是否能够相邻,这个矩阵珂以由\(s1\)得出.答案显然是矩阵\(A^{len_{s2}-1}\)的所有元素之 ...

  4. 处女篇:自用C#后端SqlHelper.cs类

    自用SqlHelper.cs类,此类来自软谋教育徐老师课程SqlHelper.cs! using System; using System.Collections; using System.Coll ...

  5. The driver is automatically registered via the SPI and manual loading of the driver class....

    Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdb ...

  6. mysql 8.0.17 安装与使用

    目录 写在前面 MySQL 安装 重置密码 使用图形界面软件 Navicat for SQL 写在前面 以前包括现在接到的项目,用的最多的关系型数据库就是SqlServer或者Oracle.后来因为接 ...

  7. k8s安装部署问题、解决方案汇总

    角色 节点名 节点ip master n1 192.168.14.11 节点1 n2 192.168.14.12 节点2 n3 192.168.14.13 https://raw.githubuser ...

  8. 微软企业库支持 MySql

    微软企业库支持 MySql   三步让企业库支持 mysql 数据库 1.创建 MySqlDatabaseData 类 using Microsoft.Practices.EnterpriseLibr ...

  9. Docker 四种网络模式

    原文 https://www.cnblogs.com/gispathfinder/p/5871043.html 我们在使用docker run创建Docker容器时,可以用--net选项指定容器的网络 ...

  10. Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作

    Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作,单表查询,多表查询 一丶表与表之间的关系 背景: ​ ​ ​  ​ ​ 由于如果只使用一张表存储所有的数据,就会操作数 ...