【发布时间】:2013-12-19 16:00:55
【问题描述】:
为广泛使用 longjmp 和多个跳转目标进行错误管理的旧 C 代码生成 C++ API 的正确方法是什么?
我的想法是编写一个函数,为每个使用的目标设置跳转目标,例如:
void catchJumps() {
if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
if (setjmp(target2)) throw Error2();
//...
}
然后我会在每个使用 C 代码的 C++ 函数(更具体地,在每个范围内)中调用 catchJumps:
int some_wrapper() {
catchJumps();
callCFunction()
for (int i = 0; i < 1000; i++) {
catchJumps();
callOtherCFunction();
}
catchJumps();
callOneMoreCFunction();
callEvenOneMoreCFunction();
}
这是在不破坏堆栈的情况下捕获所有跳远的安全方法吗?我知道,将 longjmp 放入不同的堆栈帧是很危险的。现在我的函数catchJumps 位于另一个堆栈帧中,而不是调用some_wrapper。我希望(或者我什至可以做到)catchJumps 可以被内联,这样框架是一样的,但我不知道。
每个作用域中的调用(以及上面的循环之后)应该是所有作用域对象的析构函数都被调用的必要条件,对吧?
如果这不是将 longjmps“转换”为调用应用程序的断言的有效方法,我们还能做什么?
【问题讨论】:
-
“我知道,将 longjmp 放入不同的堆栈帧很危险。”这实际上是 longjmp 的 全部要点,只要您 展开 到前一帧,这并不是特别危险,换句话说,您不会 longjmp 到一个函数已经回来了。 C++ 运行时还提供了
longjmp的实现,可以正确展开堆栈帧,因此使用起来很安全(即使不鼓励使用)。 -
那可能行不通。跳转目标位于
catchJumps中,这是一个在发生长跳转时不再位于堆栈上的例程。宏是“隐藏”跳远的最佳选择。这是否是个好主意是另一个问题。 -
另外,你能访问图书馆的源代码吗?
-
@zneak:是的,但不能将库中的 longjmps 更改为其他内容,因为它用于不同的项目。
-
如果重新编译库是一种选择,我建议您将
setjmp定义为空,将longjmp(x)定义为throw &x。这样,您将能够捕获jmpbuf_t*,并且您将能够通过简单的相等性检查来检查它是哪一个,而对源代码的干扰最小。