关于以下内容在linux/gcc上使用C++中的longjmp和setjmp是否安全?
*this
指针我很想知道如何在OCaml运行时处理异常以使它们如此轻量级.他们使用setjmp/longjmp还是在每个函数中返回一个特殊值,然后传播它?
在我看来,longjmp会给系统带来一点压力,但只有当引发异常时,检查每个函数的返回值才需要在调用函数后检查每个值和每个值,这在我看来会很多检查和跳跃,似乎表现最差.
通过查看OCaml如何与C接口(http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc142),并查看callback.h,似乎通过使用标记异常对象的内存对齐(#define Is_exception_result(v)(((v)&3)== 2)).这似乎表明它的实现不使用longjmp并在每次函数调用后检查每个函数结果.是吗?或者C函数已经尝试捕获任何异常,然后将其转换为这种格式?
谢谢!
我必须将C用于一个项目,我正在考虑使用longjmp/setjmp
错误处理,因为我认为在一个中心位置处理错误要比返回代码容易得多.如果有一些关于如何做到这一点的线索,我将不胜感激.
如果发生任何此类错误,我特别关注正确完成资源清理.
另外,我如何处理导致多线程程序使用它们的错误?
更好的是,是否有一些C库已经存在以进行错误/异常处理?
我们知道Rf_error()
在Rcpp中应该避免调用,因为它涉及堆栈上的C++析构函数的longjmp.这就是为什么我们宁愿在Rcpp代码中抛出C++异常(喜欢throw Rcpp::exception("...")
或通过stop("...")
函数).
但是,R警告也可能导致调用Rf_error()
(此行为取决于warn
选项).所以,打电话Rf_warning()
也是有风险的.
Rcpp::sourceCpp(code = '
#include <Rcpp.h>
using namespace Rcpp;
class Test {
public:
Test() { Rcout << "start\\n"; }
~Test() { Rcout << "end\\n"; }
};
// [[Rcpp::export]]
void test() {
Test t;
Rf_warning("test");
}
')
options(warn=10)
test()
## start
## Error in test() : (converted from warning) test
Run Code Online (Sandbox Code Playgroud)
我们看到析构函数没有被调用(没有"结束"消息).
如何用C++生成R警告 - 对析构函数友好的方式?
我有这样的功能:
#include <setjmp.h>
jmp_buf buf;
void func2(int g);
extern int some_global;
void func(int x)
{
if (setjmp(buf))
return;
if (some_global)
x += 5;
func2(x);
}
Run Code Online (Sandbox Code Playgroud)
GCC(gcc(Debian 4.4.5-8)4.4.5)发出警告:
test.c: In function ‘func’: test.c:5: warning: argument ‘x’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Wclobbered]
为什么????我的意思是,显然我不在乎是否x
被破坏,因为它不可能在setjmp
返回后使用.即使编译器应该知道一些非常明显的东西,因为它具有某种特殊的知识setjmp
.
我的主要兴趣是找到我继承的代码库中的错误,因此,"使用这种编码风格"并不是我正在寻找的建议.然而,这里有许多奇怪的曲折.例如,如果x
是局部变量而不是参数,那么GCC不会抱怨.此外,GCC不会在没有if (some_global)
线的情况下抱怨.尼斯.有些事情搞砸了GCC的流量分析,或者GCC知道我不知道的事情.
所以,
是否有一种简单的方法来抑制此函数的此警告,就像您可以将未使用的参数转换为(void)
?
或者我只是在项目范围内禁止警告?
或者我错过了什么?
更新:让我与您分享一个不会产生警告的略有不同的版本:
#include <setjmp.h>
jmp_buf buf;
void func2(int g);
extern int some_global;
void func(int …
Run Code Online (Sandbox Code Playgroud) 从问题:
其中两条评论说:
"你不能在信号处理程序中抛出异常,但你可以安全地做一个longjmp - 只要你知道你在做什么. - Dietrich Epp 8月31日19:57 @Dietrich:+1你的评论.这是一个鲜为人知且完全不被重视的事实.在不使用信号处理程序的longjmp的情况下,有许多问题无法解决(令人讨厌的竞争条件).阻塞系统调用的异步中断是典型的例子."
我的印象是内核在遇到异常情况时调用信号处理程序(例如除以0).此外,如果您专门注册它们,它们只会被调用.
这似乎意味着(对我来说)它们不会通过您的正常代码调用.
继续这个想法...我理解的是setjmp和longjmp用于将堆栈折叠到先前的点和状态.我不明白在调用信号处理程序时如何折叠堆栈,因为它从内核调用作为一次性环境而不是从您自己的代码调用.从信号处理程序到堆栈的下一个东西是什么!?
是否有主要的C/C++实现,其中longjmp
函数"展开",即它与自动存储对象的析构函数__attribute__((__cleanup__(...)))
,POSIX线程取消处理程序等交互,而不仅仅是恢复由setjmp
?保存的寄存器上下文?我对使用此属性的POSIX实现的存在(或不存在)特别感兴趣,但C/C++通常也很有趣.
对于赏金,我正在寻找符合POSIX或至少类似POSIX的系统,而不是已经提到过的Windows.
我有这样的代码如下
try {
doSomething();
} catch(InterruptException) {
goto rewind_code;
}
if(0) {
rewind_code:
longjmp(savepoint, 1);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,当我goto
离开catch块时,C++运行时存储的异常对象是免费的吗?或者运行时是否允许缓存它,直到周围的函数存在或类似的东西?我只是想确保如果我多次执行上面的代码,每次采用倒带代码,我都不会泄漏内存(因为longjmp
不会执行编译器在函数序列之前或之前发出的清理代码).
我有一个特殊的函数(信号处理程序),我想检测它的递归,即确定函数是否直接或间接调用自身.棘手的一点是,该函数在一个点上调用一些不受其控制的代码,并且该代码可以执行任何操作.
通常,我只会写一些类似的东西
void foo() {
static int recursed = 0;
if(recursed) {
...
}
recursed = 1;
othercode();
recursed = 0;
}
Run Code Online (Sandbox Code Playgroud)
但在这种情况下,我担心othercode
可能会使用longjmp
或类似的突破,导致recursed
保持在1.如果我的功能以这种方式跳出来,我想确保它不会看到自己如果稍后调用则递归(事实上它longjmp
不会出现问题).
注意:我认为longjmp
可能.该othercode
是从其他一些在最狂野的代码链接的信号处理程序,并确实存在于如处理器SIGSEGV
,其使用longjmp
还原环境(例如,作为"故障保护"异常处理程序).请注意,longjmp
在同步信号处理程序中使用通常是安全的.在任何情况下,我都不特别在意其他代码是否安全,因为它不是我能控制的.