[译]C++异常的幕后18:获取正确的栈帧

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

内容简介:我们最新的personality函数知道它是否可以处理一个异常(假设每个try块仅有一条catch语句,并假设没有使用继承),不过要使得这个知识有用,我们首先需要检查我们可以处理的异常是否匹配抛出的异常。我们试着做一下。当然,我们首先需要知道异常类型。要这样做,在调用__cxa_throw时,我们需要保存异常类型(这是ABI给予我们设置所有自定义数据的机会):

作者: nicolasbrailo

我们最新的personality函数知道它是否可以处理一个异常(假设每个try块仅有一条catch语句,并假设没有使用继承),不过要使得这个知识有用,我们首先需要检查我们可以处理的异常是否匹配抛出的异常。我们试着做一下。

当然,我们首先需要知道异常类型。要这样做,在调用__cxa_throw时,我们需要保存异常类型(这是ABI给予我们设置所有自定义数据的机会):

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

1

2

3

4

5

6

7

8

9

10

11

12

void __cxa_throw(void* thrown_exception,

                 std::type_info *tinfo,

                 void (*dest)(void*))

{

    __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);

 

    // We need to save the type info in the exception header _Unwind_ will

    // receive, otherwise we won't be able to know it when unwinding

    header->exceptionType = tinfo;

 

    _Unwind_RaiseException(&header->unwindHeader);

}

现在我们可以在personality函数里读异常类型,很容易检查是否异常类型是否匹配(异常名是C++字符串,因此执行一次==足够了):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// Get the type of the exception we can handle

const void* catch_type_info = lsda.types_table_start[ -1 * type_index ];

const std::type_info *catch_ti = (const std::type_info *) catch_type_info;

 

// Get the type of the original exception being thrown

__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;

std::type_info *org_ex_type = exception_header->exceptionType;

 

printf("%s thrown, catch handles %s\n",

            org_ex_type->name(),

            catch_ti->name());

 

// Check if the exception being thrown is of the same type

// than the exception we can handle

if (org_ex_type->name() != catch_ti->name())

    continue;

这里 有新修改的完整源代码。当然如果我们加入这,将有问题(你能看出来吗)。如果在两阶段里抛出异常,并且我们说在第一阶段我们能处理它,那么我们不能在第二阶段再说我们不想要它。我不知道_Unwind_是否根据任何文档处理这个情形,但这最有可能要求未定义的行为,因此只是说我们将处理一切是不足够的。

因为我们给予了personality函数知道着陆垫是否可以处理要抛出异常的能力,我们一直欺骗_Unwind_我们可以处理的异常;即使在我们的 ABI 9 上我们说处理所有的异常,真相是我们不知道我们是否能够处理它。这很容易修改,我们可以像这样做:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

_Unwind_Reason_Code __gxx_personality_v0 (...)

{

    printf("Personality function, searching for handler\n");

 

    // ...

 

    foreach (call site entry in lsda)

    {

        if (call site entry.not_good()) continue;

 

        // We found a landing pad for this exception; resume execution

 

        // If we are on search phase, tell _Unwind_ we can handle this one

        if (actions & _UA_SEARCH_PHASE) return _URC_HANDLER_FOUND;

 

        // If we are not on search phase then we are on _UA_CLEANUP_PHASE

        /* set everything so the landing pad can run */

 

        return _URC_INSTALL_CONTEXT;

    }

 

    return _URC_CONTINUE_UNWIND;

}

同样,在我的 github repo 里获取项目的源代码。

好了,如果运行带有这个修改的personality函数我们会得到什么?失败了,这就是我们得到的!记得我们的抛出函数吗?这个应该捕捉我们的异常:

1

2

3

4

5

6

7

8

9

10

11

void catchit() {

    try {

        try_but_dont_catch();

    } catch(Fake_Exception&) {

        printf("Caught a Fake_Exception!\n");

    } catch(Exception&) {

        printf("Caught an Exception!\n");

    }

 

    printf("catchit handled the exception\n");

}

不幸,我们的personality函数仅检查着陆垫可以处理的第一个类型。如果我们删除Fake_Exception块再尝试,我们得到另一位故事:最终,成功了!我们的personality函数现在可以在正确的帧里选择正确的catch,只要没有带有多个catch的try块。

下一次我们将进一步改进它。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

图解CSS3

图解CSS3

廖伟华 / 机械工业出版社 / 2014-7-1 / CNY 79.00

本书是CSS3领域的标准性著作,由资深Web前端工程师根据CSS3的最新技术标准撰写。内容极为全面、丰富和翔实,由浅入深地讲解了CSS3新特性的语法、功能和使用技巧,涵盖选择器、边框、背景、文本、颜色、UI、动画、新型盒模型、媒体查询、响应式设计等各种模块;写作方式创新,有趣且易懂,用图解的方式来描述CSS3的每一个特性甚至每一个步骤都配有实战效果图;包含大量案例,实战性强,每个特性都有作者从实践......一起来看看 《图解CSS3》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具