安全使用`setjmp`和`longjmp`

时间:2015-09-14 08:02:45

标签: c performance memory-leaks longjmp setjmp

我知道人们总是说不要使用longjmp,这是邪恶的,这很危险。

但我认为它可以用于退出深度递归/嵌套函数调用。

单个longjmpif(returnVal != SUCCESS) return returnVal;等重复检查和返回更快吗?

至于安全性,只要动态释放动态内存和其他资源,就不会出现问题,对吗?

到目前为止似乎使用longjmp并不困难,它甚至使我的代码更加严格。我很想使用它。

(恕我直言,在很多情况下,首先在深度递归中没有分配动态内存/资源。深度函数调用似乎更常见于数据解析/操作/验证。动态分配通常在更高级别发生,然后再调用setjmp出现的函数。)

2 个答案:

答案 0 :(得分:4)

setjmplongjmp可被视为穷人的exception机制。 BTW,Ocaml例外与setjmp一样快,但语义更清晰。

当然,longjmp比在中间函数中重复返回错误代码要快得多,因为它会弹出一个可能很重要的call stack部分。

(我暗中关注Linux)

只要没有在它们之间分配资源,它们就是有效且有用的,包括:

  • 堆内存(malloc
  • fopen - ing FILE*句柄
  • 打开操作系统文件描述符(例如,用于套接字)
  • 其他操作系统资源,例如计时器或信号处理程序
  • 获取某些服务器管理的外部资源,例如X11窗口(因此使用任何小工具工具包,如GTK),或数据库句柄或连接......
  • 等...

主要问题是leaking resources的属性是全局整个程序属性(或者至少是所有可能在{之间调用的函数的全局属性) {1}}和setjmp),因此它禁止modular software development:任何其他同事必须在longjmpsetjmp之间的任何功能中改进某些代码时必须注意这一点限制并遵循该规则。

因此,如果您非常清楚地使用 longjmp文档。

顺便说一句,如果您关心setjmp,系统地使用 Boehm's保守garbage collector会有很大帮助;您将在任何地方使用malloc代替GC_malloc,而您不会关心malloc,实际上这就足够了;然后,您可以毫无顾虑地使用free(因为您可以在setjmpGC_malloc之间拨打setjmp

(请注意,垃圾收集器的概念和术语与异常处理和longjmp密切相关,但很多人对它们了解不够。阅读Garbage Collection Handbook应该是值得的)功能

另请阅读RAII并了解C++11例外情况(及其与destructors的关系)。了解continuationsCPS

阅读setjmp(3)longjmp(3)(以及约setjmpsigsetjmpsetcontext(3))并注意编译器必须了解{{ 1}}

答案 1 :(得分:2)

您应该注意,在某些上下文中调用setjmp并不能保证安全(例如,您无法移植存储setjmp的返回值)。

另外,如果你想在调用setjmp后访问局部变量,在同一个函数中,可能已经改变了,你应该将变量标记为volatile。

使用setjmp和longjmp也很有用,因为如果递归导致堆栈溢出,您可以使用信号处理程序中的longjmp进行恢复(不要忘记设置备用堆栈)并返回错误。如果你想这样做,你应该考虑使用sigsetjmp和siglongjmp来保存信号处理。