是否可以在C中编写零成本的异常处理?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否可以在C中编写零成本的异常处理?相关的知识,希望对你有一定的参考价值。
g ++编译器具有零成本异常处理的功能。据我了解,try
不执行任何操作,但是当引发异常时,将执行异常处理程序的子例程。像这样:
void foo()
try
bar(); // throws.
catch (Type exc)
baz();
用伪代码(c-stylish)看起来像这样:
void foo()
bar();
return;
catch1_Type:
baz();
bar()抛出。异常例程执行以下操作:
啊,返回地址在函数foo()中!返回地址位于第一个try-catch块中,我们抛出Type类型,因此异常处理程序例程位于地址foo + catch1_Type处。因此,清理堆栈,以便最终结束!
现在我的问题:有什么方法可以在C中实现它? (虽然我对gcc支持的C语言感兴趣,但可以是C99或更高版本)。我知道我可以使用例如libunwind进行堆栈检查和遍历,尽管我不知道如何获取catch1_Type
标签的地址。可能不可能。
异常处理程序可能是一个不同的函数,这同样可以,但是如何在另一个函数中获取堆栈帧foo
的局部变量的地址呢?这似乎也是不可能的。
所以...有什么办法吗?我不想与此一起进入汇编程序,但是如果其他所有操作都失败了,那也是可以接受的(尽管局部变量-伙计,如果使用不同的优化级别,您将永远不知道它们在哪里)。
并且要明确-这个问题的目的是avoid setjmp / longjmp方法。
编辑:我发现了一个很酷的主意,但不能完全起作用:
gcc中的嵌套函数。他们能做什么?
- 可以访问局部变量,
- 有可能在父函数中转到本地标签!
- 可以由我们的函数的被调用者调用,只要我们将指针传递给嵌套函数,那么它就可以被被调用者中的指针使用。
不利于我做零成本的事情的缺点:
- 如果未使用它们,即使在-O0级别,它们也会被优化。我可以对此做任何事情吗?如果可以的话,可以在抛出异常时按符号名称获取地址,这将只是实现异常的工作,而在不抛出异常的情况下,它会花费大量的时间...
我已经花了一些时间来解决这个想法,我已经很接近为我自己的问题找到解决方案了。这是详细信息:
- gcc允许嵌套函数访问父函数的局部变量,并且可以转到父函数中的标签!
- gcc如果仅定义但未引用,则不会为内部函数发出代码。您可以定义内联无操作函数,该函数获取指向本地函数的指针,并在父函数中调用它。这将强制为内部函数生成代码,并且成本为零(在更高的优化级别,将删除嵌入式无操作调用)。但是,在最新的gcc中,优化内联调用可能会阻止为内部函数生成代码。
- 糟糕的是,我看不出有什么方法可以将嵌套(内部)函数强制为全局符号。它们始终是本地的,因此无法使用dlsym获取地址。
- 另一个坏消息,如果程序正在使用此类嵌套函数,则valgrind将崩溃;)我能够验证我的简单测试程序,但无法使用valgrind来验证是否没有内存冲突。
我用于检查的代码有明显的缺陷:它不是'零成本',因为必须在函数执行期间设置指向异常处理例程的全局指针。如果可以的话,我们可以编译一下!
好吧,毕竟,如果要使用内部函数,就像将指向它的指针传递给被调用者一样,以便他们在引发异常的情况下可以调用它,我们可能可以非常快速地进行异常处理,比setjmp / longjmp ...
[我将继续进行黑客攻击,也许我会找到一种方法(一些汇编代码块强制GAS将功能注册为父代的个性例程?)。
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
typedef void (*catch_routine)(void*);
catch_routine g_r = NULL;
void tostr_internal(char* str, int a)
int result = a + 'a';
if (result < 'a' || result > 'z')
// handle exception
if(g_r)
g_r(&a);
else
fprintf(stderr, "Exception not caught!");
abort();
else
str[0] = result;
str[1] = '\0';
char* tostring(int a)
__label__ exhandler;
char* string = (char*)malloc(2*sizeof(char));
void personality(void* exid)
fprintf(stderr, "Number %d is not a character!\n", *(int*)(exid));
free(string);
goto exhandler;
g_r = personality;
tostr_internal(string, a);
return string;
exhandler:
return NULL;
int main(int a, char** b)
int i = 0;
for(i = 0; i < 10000; i++)
int trythisbastard = i % 95;
char* result = tostring(trythisbastard);
if (result)
fprintf(stderr, "Number %d is %s\n", trythisbastard, result);
free(result);
return 0;
当我需要在C中使用try / catch类似功能时,我使用了本文。
以上是关于是否可以在C中编写零成本的异常处理?的主要内容,如果未能解决你的问题,请参考以下文章
从零开始的Java开发1-5-1 异常:分类异常处理try-catch-finally多重catchfinally与returnthrowsthrow关键字自定义异常类异常链