2015-02-12 84 views
3

我的项目是用C++编写的,它利用动态生成的代码将一些东西粘合在一起(使用Fabrice Bellard的TCC和一些手动生成的汇编thunk )。动态生成的代码有时会跳转到用C++实现的“运行时帮助程序”中。C++和跳出动态生成代码的安全方式

有一个功能,允许完全中止动态生成的代码,无论它在哪里,都跳回到C++(调用者)。为了达到这个目的,我简单地使用C++异常:一个运行时帮助器(作为C函数)简单地抛出一个C++异常,并且它通过生成的函数传播回C++。我正在使用SJLJ,目前为止一切正常,但我不想依赖于某个特定实现(我读到只有SJLJ才安全)。

除了上面的中止方案,我的C++代码主要在关键情况下使用异常,它不用于通用控制流。但是,我依靠RAII自动破坏堆栈中的对象。

我的问题是:它是理论和实践上安全使用的longjmp/setjmp的替代,提供了setjmp设置正确调用动态生成的函数之前,并规定longjmp的从未到C传播++函数依赖RAII(我必须确保没有在C++中实现的运行时帮助程序使用它),并始终登陆setjmp(在函数之前设置)?

或者C++太脆弱了,即使这样也不能保证能正常工作并会损坏某些东西?或者,也许C++只有在抛出实际异常时才会中断?如果异常在本地抛出并立即被捕获(在生成的程序集调用的运行时助手中),它会安全吗?或者,也许只是因为有一些外来的框架,它会拒绝工作?

EG:

jmp_buf buf; // thread-local 
char* msg; // thread-local 

// ... some C++ code here, potentially some RAII thingy 

GeneratedFunc func = (GeneratedFunc)compile_stuff(); 
if (!setjmp(buf)) { 
    // somewhere deep inside, it calls longjmp to jump back to the top function in case a problem happens 
    func(); 
} else { 
    printf("error: %s\n", msg); 
    // do something about the error here 
} 

// some other C++ code 
+0

是否可以勾画出一些源代码/伪代码来说明如何使用'longjmp/setjmp'? – 2015-02-12 03:20:24

+0

这里伪代码http://pastebin.com/fTE3brK4 – carsten 2015-02-12 03:33:28

回答

1

它是理论上和实践上使用安全的longjmp/setjmp的代替,提供了setjmp是正确的呼叫动态生成函数之前设置,且条件是longjmp的从未至C传播++函数依赖于RAII(我必须确保没有在C++中实现的运行时帮助程序使用它)并始终登陆setjmp(在函数之前设置)?

标准的18.10/4说:

... longjmp(jmp_buf jbuf, int val)在本国际标准更严格的行为。 A setjmp/longjmp呼叫对具有未定义的行为,如果将setjmplongjmp替换为catchthrow将为任何自动对象调用任何非平凡的析构函数。

所以,它不只是RAII,但任何堆栈主办与非平凡的析构函数(即“资源”后建设可能被收购反对,但仍需要销毁时被释放,或者有可能是侧除资源释放之外的其他破坏效应,如日志记录)。

或者C++太脆弱了,即使这样也不能保证能够正常工作并会破坏某些东西?

它应该工作受限于琐碎析构函数(这是一个相当大的限制)上面的警告。

或者,也许C++只打破了实际的异常?如果异常在本地抛出并立即被捕获(在生成的程序集调用的运行时助手中),它会安全吗?

这与setjmp/longjmp行为无关。如果你在正常的C++编译器生成的代码中抛出并捕获,那么执行(重新)输入动态生成的代码时不应该有任何残留/结果问题。同样的方法用于从C调用/打包的C++库;异常可能会在C++库的边界上被捕获并转换为C可以处理的错误代码。

+0

那么,这意味着如果setjmp/longjmp之间的析构函数被忽略,它们只是不安全的?我担心当析构函数与setjmp具有相同的功能时,它会破坏某些东西,因为谁知道用什么样的魔法来实现异常。 – carsten 2015-02-12 03:53:03

+0

P.S.通过“析构函数”,我也意味着整个潜在的堆栈展开事件(为了支持它而发布的本地内部代码) – carsten 2015-02-12 04:00:32

+0

@carsten *“这意味着setjmp/longjmp只是在它们之间的析构函数被忽略时才不安全?” - 意思是......如果在跳转过程中你的意思是“未执行”,那么析构函数肯定会被“忽略”,所以危险是当它们被忽略时,必要的破坏行为不会被执行,并且标准的操作保证相当薄弱:如果所讨论的所有析构函数都不是微不足道的,则行为是不确定的。请参阅[这里](http://stackoverflow.com/questions/8190879/what-is-a-non-trivial-destructor-in-c)解释这是什么意思。 – 2015-02-12 04:26:04