SIGSEGV 不能被 sigaction 捕获两次
SIGSEGV cannot be caught twice with sigaction
以下代码在第二个 printf
处存在分段错误,而这应该得到处理 (setjmp
)。请注意,每个 printf
由于错误的格式字符串而创建分段错误。第一个分段错误得到了正确处理,但第二个却没有(运行 注释掉 printf
后的代码不会出现段错误)。
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
static jmp_buf escapeCallJmpBuf;
static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
longjmp(escapeCallJmpBuf, 1);
}
int main(int argc, char **argv) {
struct sigaction segvAction, segvActionOld;
segvAction.sa_handler = 0;
memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
segvAction.sa_flags = SA_SIGINFO;
segvAction.sa_sigaction = sigsegv_handler;
sigaction(SIGSEGV, &segvAction, &segvActionOld);
int res;
// Catch first segmentation fault
if (setjmp(escapeCallJmpBuf)) {
res = 1;
} else {
printf ("%s\n", 2); // This will segfault
res = 0;
}
// try to catch second segmentation fault
if (setjmp(escapeCallJmpBuf)) {
res = 2;
} else {
printf ("%s\n", 3); // This will segfault
res = 0;
}
sigaction(SIGSEGV, &segvActionOld, 0);
return res;
}
setjmp
和 longjmp
不一定恢复信号掩码(取决于实现)。可能发生的情况是在处理完第一个 SIGSEGV 后,信号掩码恢复为默认值。所以第二个 SIGSEGV 没有被捕获,即默认操作发生而不是你的,这是退出进程。
您应该改用 sigsetjmp
和 siglongjmp
。
POSIX 状态:
It is unspecified whether longjmp() restores the signal mask, leaves the signal mask unchanged, or restores it to its value at the time setjmp() was called.
并建议:
Applications whose behavior depends on the value of the signal mask
should not use longjmp() and setjmp(), since their effect on the
signal mask is unspecified, but should instead use the siglongjmp()
and sigsetjmp() functions (which can save and restore the signal mask
under application control).
此外,从信号处理程序跳转有限制:
It is recommended that applications do not call longjmp() or
siglongjmp() from signal handlers. To avoid undefined behavior when
calling these functions from a signal handler, the application needs
to ensure one of the following two things:
After the call to longjmp() or siglongjmp() the process only calls
async-signal-safe functions and does not return from the initial call
to main().
Any signal whose handler calls longjmp() or siglongjmp() is blocked
during every call to a non-async-signal-safe function, and no such
calls are made after returning from the initial call to main().
以下代码在第二个 printf
处存在分段错误,而这应该得到处理 (setjmp
)。请注意,每个 printf
由于错误的格式字符串而创建分段错误。第一个分段错误得到了正确处理,但第二个却没有(运行 注释掉 printf
后的代码不会出现段错误)。
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
static jmp_buf escapeCallJmpBuf;
static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
longjmp(escapeCallJmpBuf, 1);
}
int main(int argc, char **argv) {
struct sigaction segvAction, segvActionOld;
segvAction.sa_handler = 0;
memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
segvAction.sa_flags = SA_SIGINFO;
segvAction.sa_sigaction = sigsegv_handler;
sigaction(SIGSEGV, &segvAction, &segvActionOld);
int res;
// Catch first segmentation fault
if (setjmp(escapeCallJmpBuf)) {
res = 1;
} else {
printf ("%s\n", 2); // This will segfault
res = 0;
}
// try to catch second segmentation fault
if (setjmp(escapeCallJmpBuf)) {
res = 2;
} else {
printf ("%s\n", 3); // This will segfault
res = 0;
}
sigaction(SIGSEGV, &segvActionOld, 0);
return res;
}
setjmp
和 longjmp
不一定恢复信号掩码(取决于实现)。可能发生的情况是在处理完第一个 SIGSEGV 后,信号掩码恢复为默认值。所以第二个 SIGSEGV 没有被捕获,即默认操作发生而不是你的,这是退出进程。
您应该改用 sigsetjmp
和 siglongjmp
。
POSIX 状态:
It is unspecified whether longjmp() restores the signal mask, leaves the signal mask unchanged, or restores it to its value at the time setjmp() was called.
并建议:
Applications whose behavior depends on the value of the signal mask should not use longjmp() and setjmp(), since their effect on the signal mask is unspecified, but should instead use the siglongjmp() and sigsetjmp() functions (which can save and restore the signal mask under application control).
此外,从信号处理程序跳转有限制:
It is recommended that applications do not call longjmp() or siglongjmp() from signal handlers. To avoid undefined behavior when calling these functions from a signal handler, the application needs to ensure one of the following two things:
After the call to longjmp() or siglongjmp() the process only calls async-signal-safe functions and does not return from the initial call to main().
Any signal whose handler calls longjmp() or siglongjmp() is blocked during every call to a non-async-signal-safe function, and no such calls are made after returning from the initial call to main().