C++异常的幕后20:在回滚时运行析构函数

原文地址:https://monoinfinito.wordpress.com/2013/05/28/c-exceptions-under-the-hood-20-running-destructors-while-unwinding/

作者:nicolasbrailo

上次我们编写的小ABI版本11能够处理相当多处理异常的基本情况:我们有一个(几乎奏效的)能够抛出与捕捉异常的ABI,但它仍然不能正确运行析构函数。如果我们希望编写异常安全代码,这相当重要。通过我们对.gcc_except_table的了解,运行析构函数小菜一碟,我们只需看一点汇编:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

# Call site table

.LLSDACSB2:

    # Call site 1

    .uleb128 ip_range_start

    .uleb128 ip_range_len

    .uleb128 landing_pad_ip

    .uleb128 (action_offset+1) => 0x3

     

    # Rest of call site table

 

# Action table start

.LLSDACSE2:

    # Action 1

    .byte   0

    .byte   0

 

    # Action 2

    .byte   0x1

    .byte   0x7d

 

    .align 4

    .long   _ZTI14Fake_Exception

.LLSDATT2:

# Types table start

在一个规范的着陆垫上,当一个活动有大于0的类型索引时,它意味着我们看到类型表的一个索引,我们可以使用它来了解该catch可以处理哪些类型;对于具有值0的类型索引,这意味着我们看到一个清理块,无论如何都要运行它。虽然着陆垫不能处理异常,它将仍然能够执行清理,在回滚时这预期发生。当然,在完成清理时,着陆垫将调用_Unwind_Resume,这将继续正常的栈回滚过程。

我已经将这个最新版本上传到我的githut repo里,不过有有些新的坏消息:记得我们如何通过说uleb128 == char来欺骗的吗?一旦我们开始增加块来运行析构函数,.gcc_except_table开始变得相当大(“大”意味着我们有超过127字节长度的偏移),这个假设不再成立。

对这个ABI的下一个版本,我们必须重写读LSDA的函数来读正确的uleb128码。不是一个大的改动,但此时我们不会有太大的收获,我们已经实现了我们的目标:一个无需libcxxabi辅助能够处理异常的工作的最小ABI。

存在我们还没涉及的部分,像处理非原生异常,捕捉衍生类型以及编译器与链接器间的互操作。也许在其他时间,在这个相当长的系列里,我们已经学到相当多的了C++里底层如何处理异常的知识。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值