[译]C++异常的幕后4:捕捉你抛出的异常

栏目: C++ · 发布时间: 6年前

内容简介:在这个关于异常处理的系列里,通过检查编译器与链接器错误,我们已经发现不少异常抛出的秘密,但目前为止我们还看到任何关于异常处理的东西。让我们总结一下学到的异常抛出:目前为止相当简单,但异常捕捉有点复杂,特别因为它要求某种程度的反射(即,程序分析自己源代码的能力)。让我们继续在旧代码上尝试,在我们代码添加一些catch语句,编译它并看发生了什么:

作者: nicolasbrailo  

在这个关于异常处理的系列里,通过检查编译器与链接器错误,我们已经发现不少异常抛出的秘密,但目前为止我们还看到任何关于异常处理的东西。让我们总结一下学到的异常抛出:

  • 一个throw语句将被编译器翻译为两个调用,__cxa_allocate_exception与__cxa_throw。
  • __cxa_allocate_exception与__cxa_throw“活”在libstdc++中。
  • __cxa_allocate_exception将为新异常分配内存。
  • __cxa_throw将准备一大堆东西并把这个异常转发给_Unwind_,一组libstdc++里的函数,并执行真正的栈回滚(这个 ABI 定义了这些函数的接口)。

目前为止相当简单,但异常捕捉有点复杂,特别因为它要求某种程度的反射(即,程序分析自己源代码的能力)。让我们继续在旧代码上尝试,在我们代码添加一些catch语句,编译它并看发生了什么:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

#include "throw.h"

#include <stdio.h>

 

// Notice we're adding a second exception type

struct Fake_Exception {};

 

void raise() {

    throw Exception();

}

 

// We will analyze what happens if a try block doesn't catch an exception

void try_but_dont_catch() {

    try {

        raise();

    } catch(Fake_Exception&) {

        printf("Running try_but_dont_catch::catch(Fake_Exception)\n");

    }

 

    printf("try_but_dont_catch handled an exception and resumed execution");

}

 

// And also what happens when it does

void catchit() {

    try {

        try_but_dont_catch();

    } catch(Exception&) {

        printf("Running try_but_dont_catch::catch(Exception)\n");

    } catch(Fake_Exception&) {

        printf("Running try_but_dont_catch::catch(Fake_Exception)\n");

    }

 

    printf("catchit handled an exception and resumed execution");

}

 

extern "C" {

    void seppuku() {

        catchit();

    }

}

备注:你可以从我的 github repo 下载完整的源代码。

就像之前那样,我们的seppuku函数把C世界与C++世界链接起来,只是这次我们添加了另外一些函数调用来使得我们的栈更有趣,加上我们已经添加了一组try/catch块,因此我们可用分析libstdc++如何处理它们。

像以前那样,我们得到了一些关于缺失ABI函数的链接器错误:

1

2

3

4

5

6

7

8

9

10

11

12

13

> g++ -c -o throw.o -O0 -ggdb throw.cpp

> gcc main.o throw.o mycppabi.o -O0 -ggdb -o app

throw.o: In function `try_but_dont_catch()':

throw.cpp:12: undefined reference to `__cxa_begin_catch'

throw.cpp:12: undefined reference to `__cxa_end_catch'

 

throw.o: In function `catchit()':

throw.cpp:20: undefined reference to `__cxa_begin_catch'

throw.cpp:20: undefined reference to `__cxa_end_catch'

 

throw.o:(.eh_frame+0x47): undefined reference to `__gxx_personality_v0'

 

collect2: ld returned 1 exit status

同样这里我们看到了许多有趣的东西。对__cxa_begin_catch与__cxa_end_catch的调用可能是我们期望的东西:我们尚不了解它们,但我们可以假定它们等同于throw/__cxa_allocate/throw转换(记得我们的throw关键字被翻译为一对__cxa_allocate_exception与__cxa_throw函数,对吧?)。不过__gxx_personality_v0是新玩意,它是后面几章的中心。

Personality函数做什么用呢?在介绍这个系列时,我们谈论过它,但我们将进一步探究它,连同我们的两个新朋友,__cxa_begin_catch与__cxa_end_catch。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

老码识途

老码识途

韩宏 / 电子工业出版社 / 2012-8 / 56.00元

《老"码"识途:从机器码到框架的系统观逆向修炼之路》以逆向反汇编为线索,自底向上,从探索者的角度,原生态地刻画了对系统机制的学习,以及相关问题的猜测、追踪和解决过程,展现了系统级思维方式的淬炼方法。该思维方式是架构师应具备的一种重要素质。《老"码"识途:从机器码到框架的系统观逆向修炼之路》内容涉及反汇编、底层调试、链接、加载、钩子、异常处理、测试驱动开发、对象模型和机制、线程类封装、跨平台技术、插......一起来看看 《老码识途》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具