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

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

内容简介:我们最新的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块。

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


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

查看所有标签

猜你喜欢:

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

Python Algorithms

Python Algorithms

Magnus Lie Hetland / Apress / 2010-11-24 / USD 49.99

Python Algorithms explains the Python approach to algorithm analysis and design. Written by Magnus Lie Hetland, author of Beginning Python, this book is sharply focused on classical algorithms, but it......一起来看看 《Python Algorithms》 这本书的介绍吧!

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

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器