【发布时间】:2015-04-12 15:58:18
【问题描述】:
我的项目是用 C++ 编写的,它利用动态生成的代码将一些东西粘合在一起(使用 Fabrice Bellard 的 TCC 和一些手动生成的程序集 thunk)。动态生成的代码有时会跳转到用 C++ 实现的“运行时助手”并返回。
有一个功能允许完全中止动态生成的代码,无论它在哪里,跳回 C++(调用者)。为了实现这一点,我只是使用 C++ 异常:运行时帮助程序(伪装成 C 函数)简单地抛出 C++ 异常,并通过生成的函数传播回 C++。我正在使用 SJLJ,到目前为止一切正常,但我不想依赖特定的实现(我读到只有 SJLJ 才安全)。
除了上面的中止方案,我的 C++ 代码主要在紧急情况下使用异常,它不用于通用控制流。但是,我依靠 RAII 自动销毁堆栈上的对象。
我的问题是: 使用 longjmp/setjmp 在理论上和实践上是否安全,前提是 setjmp 在调用动态生成的函数之前设置,并且 longjmp 永远不会通过依赖在 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
【问题讨论】:
-
是否可以勾勒出一些源代码/伪代码来说明您希望如何使用
longjmp/setjmp? -
这里是伪代码pastebin.com/fTE3brK4