如果一个人最终陷入使用 setjmp/longjmp (don't ask)卡住的情况,那么编译器会发出很多很好的警告,说明你什么时候做错了。
但是在 Clang 中-Wall -Wextra -pedantic
使用Address Sanitizer进行构建时,我得到了一个大致平行于以下内容的案例:
void outer() {
jmp_buf buf;
ERR error;
if (setjmp(buf) ? helper(&error) : FALSE) {
// process whatever helper decided to write into error
return;
}
// do the stuff you wanted to guard that may longjmp.
// error is never modified
}
在 longjmp 上,查看helper
堆栈帧时,错误指针为空。如果我查看outer()
框架,它会说错误已“优化”。
这很令人费解,因为我正在编译-O0
所以“优化出来”的说法很奇怪。但是与longjmp-y的大多数事情一样,我想知道是什么让编译器无法决定它将提前将错误地址放入哪个寄存器......然后让它失效。
地址消毒剂是在打我吗,还是我实际上必须写如下内容:
void outer() {
jmp_buf buf;
ERR error;
volatile ERR* error_ptr = &error;
if (setjmp(buf) ? helper(error_ptr) : FALSE) {
// process whatever helper decided to write into error
return;
}
// do the stuff you wanted to guard that may longjmp.
// error is never modified
}
当我对此进行研究时,我注意到jmp_buf
在我看到的任何示例中 s 都不是本地人。那是你不能做的事情吗?:-/
注意:有关构造的“语言律师”问题,请参阅下面的@AnT 的回答和评论setjmp() ? ... : ...
。但我实际上在这里发生的事情原来是函数退出后的一个损坏的 longjmp 调用。根据longjmp()
文档(也:常识),这绝对是错误的;我只是没有意识到这就是发生的事情:
如果调用 setjmp 的函数已退出,则行为未定义(换句话说,只允许长跳转调用堆栈)