我的项目是用 C++ 编写的,它利用动态生成的代码将一些东西粘合在一起(使用 Fabrice Bellard 的TCC和一些手动生成的程序集 thunk)。动态生成的代码有时会跳转到用 C++ 实现的“运行时助手”并返回。
有一个功能允许完全中止动态生成的代码,无论它在哪里,跳回 C++(调用者)。为了实现这一点,我只是使用 C++ 异常:运行时帮助程序(伪装成 C 函数)简单地引发 C++ 异常,并通过生成的函数传播回 C++。我正在使用SJLJ,到目前为止一切正常,但我不想依赖特定的实现(我读到只有 SJLJ 才安全)。
除了上面的中止方案,我的 C++ 代码主要在危急情况下使用异常,它不用于通用控制流。但是,我依靠 RAII 自动销毁堆栈上的对象。
我的问题是:如果 setjmp 在调用动态生成的函数之前正确设置,并且 longjmp 永远不会通过依赖 RAII 的 C++ 函数传播(我必须确保没有用 C++ 实现的运行时助手使用它)并且总是落在 setjmp (在函数之前设置)?
或者 C++ 是如此脆弱以至于不能保证它能够正常工作并且会破坏某些东西?或者也许只有在抛出实际异常时 C++ 才会中断?如果异常在本地抛出并立即捕获(在生成的程序集调用的运行时助手中)怎么办,它安全吗?或者可能只是因为堆栈中有一些外来帧,它会拒绝工作?
例如:
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