参考 Exceptions in C with Longjmp and Setjmp 写了下面一段程序:
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
jmp_buf ex_buf__;
#define TRY do{ if(!setjmp(ex_buf__)) {
#define CATCH } else {
#define ETRY } } while(0)
#define THROW longjmp(ex_buf__, 1)
void sigint_handler(int sig) {
THROW;
}
int main(void) {
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
return 0;
}
TRY {
while (1) {
printf("Run...\r");
}
/* raise(SIGINT); */
} CATCH {
printf("KeyboardInterrupt");
}
ETRY;
return 0;
}
本来是希望在程序运行时, 按下 Ctrl-C
后会的到输出: KeyboardInterrupt
.
然而实际运行的时候程序崩溃了。 崩溃前的输出依然是 Run...
.
假如将 while
部分用 raise(SIGINT)
替代可以得到期望的结果。
这是为什么呢 ? 是不是和死循环有什么关系 ?
编译环境:
-
编译器:
gcc version 7.2.0 (x86_64-win32-seh-rev1, Built by MinGW-W64 project)
clang version 5.0.1 (tags/RELEASE_501/final) Target: x86_64-pc-windows-msvc Thread model: posix
两个的运行结果是一样的。
-
操作系统:
Microsoft Windows 7
除非浮点数异常,Windows 明令禁止在信号处理函数中调用 longjmp,否则进程将崩溃(异常 C0000029 INVALID_UNWIND_TARGET)。
一定要在 signal handler 中调用 longjmp 的话,要避开 msvcr 的实现库,可改用 gcc 的 __builtin__longjmp,如下
注意:调用 __builtin_longjmp 之后不能再使用 printf,因为信号中断已经破坏它的内部状态。继续往标准输出(stdout)打印,将导致进程崩溃。
当然,最好不要在 signal handler 中使用 longjmp,以及其他非异步安全的函数,以免产生安全漏洞,或各种奇怪问题。
参考资料
[1]. https://docs.microsoft.com/en...
[2]. https://wiki.sei.cmu.edu/conf...