c++异常机制分析

c++异常机制分析

本文主要参考《C++异常机制的实现方式和开销分析》

栈帧(stack frame)

栈帧这个概念在c/c++里面是一个很重要的,是走进反汇编,了解代码底层结构的第一大步。
栈帧是编译器实现函数调用过程的数据结构,编译器正是通过该结构,通过寄存器在栈空间存取数据实现了函数的调用。
另外c++的异常机制正是通过在栈桢内部添加相关数据结构来实现的,因此先了解栈帧这一概念就显得更为重要了。

在这里插入图片描述
图1 栈帧结构图

如图1左图显示的是简略的栈帧结构,可以看到栈内依次压入了:

  • nArg1、nArg2,此为传入的形参(实参默认应从右至左入栈);
  • pRetAddr,该指针指向执行完该函数代码之后要返回的下一段代码的地址;
  • Caller's EBP,该指针指向上一级栈帧的EBP(基底指针寄存器)地址,在该函数执行完之后将EBP地址重置。

最后则是函数内部的局部变量依次入栈,这些结构实现了:传参,函数跳转,回跳,栈控制等功能,更多的相关概念可以参考blog

c++异常处理机制

c++的异常处理,主要包括了栈回退(stack unwind)机制和异常捕获机制,通过在栈帧内的相关数据结构来实现。

数据结构

上右图是引入了异常处理之后的栈帧结构,可以看到加入了一个新的数据结构:

  • piRrev,指向上一级异常的地址,实现异常向上抛出的功能,由此可见,该结构是一个单向链表;
  • piHandler ,指向完成异常处理以上两个机制必须的数据结构;
  • nStep,跟踪函数内部所有局部对象的构造和析构,每新生成一个新的对象就会自加1。

栈回退机制

在c++异常处理中,是没有finally:段的,但是依然能够自动实现触发异常后,对象得到正确析构,内存能够正确回收。依靠的就是该机制。
在这里插入图片描述
图2 栈回退表数据结构

该机制依靠的是piHandler 指向的EHDL结构体内的由UNWINDTBL结构体类型组成的数组,该类型结构体有三个成员如上图2。该数组包括函数内所有对象需要回退的相关信息,包括:

  • nNextldx,下一个要执行析构的对象对应的数组下标;
  • pfnDestroyer,要执行的析构函数;
  • pObj,对应需要执行析构的对象的this指针。
    可以预见到,一旦发生异常,就会根据数组下标和所指的下一个需要执行析构的对象的下标nNextldx,实现自下而上地对所有UNWINDTBL结构体内对应的对象pObj执行对应析构函数pfnDestroyer

异常捕获机制

这部分主要是介绍c++在catch到异常后如何执行对应代码。
在这里插入图片描述
图3 try表数据结构

piHandler 指向的EHDL结构体内有另一个重要的TRYBLOCK结构体数组,里面存放则是该机制所需的数据。如上图3,该结构体内包括三个变量两个部分:

  • nBeginStepnEndStep,在本章开始介绍,,这两个整数则记录try段开始和结束时nStep的数值;
  • tblCatchBlocks,该指针指向另一个结构体数组,保存所有catch块相关信息。
    • piType,异常类型。
    • pCatchBlockEntry,指向对应catch块代码的入口地址

当代码发生异常时,通过判断此时刻nStep的值是否在[nBeginStep,nEndStep)内来确定,该异常是否处在该try段内。如果是,则会进入tblCatchBlocks内寻找对应的对应的异常类型piType,并通过入口地址pCatchBlockEntry进入对应catch块内代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值