[英]Why is my signal handler not invoked more than once here?
jmp_buf functjmp;
void sigsegv_handler(int sig) {
sio_printf("Caught sigsegv!\n");
siglongjmp(functjmp, 2);
return;
}
void foo(unsigned val) {
assert(0);
sio_printf("entered!\n");
}
int main() {
struct sigaction action;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
sigaddset(&action.sa_mask, SIGSEGV);
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
sigset_t prev_mask;
sigprocmask(SIG_BLOCK, NULL, &prev_mask);
if (sigsetjmp(functjmp, 0) == 0) {
foo(*(unsigned *)0x8);
} {
sigprocmask(SIG_BLOCK, &prev_mask, NULL);
sio_printf("jump handled!\n");
foo(*(unsigned *)0x8);
}
sio_fprintf(stderr, "how did it come here?!\n");
}
我一直在使用 gdb 調試這段代碼,我無法弄清楚為什么程序不會用我自己的處理程序處理第二個 SIGSEGV 信號,假設程序沒有接收或發送其他信號? 任何帶有 sio 前綴的函數都是 stdio 對應函數的異步安全變體。 目前,我推測這與我在從信號處理程序返回的概念中缺少的東西有關,而 longjmp 根本不這樣做。
簡短回答:通常無法在 C 程序的 SIGSEGV 后恢復。 您可能會獲得更多的 C++ 里程。
長答案:請參閱在違反分段后恢復生機中的討論
假設可以冒未定義行為的風險:
可以重新啟用 SEGV。 核心問題是在信號處理期間,代碼顯式地阻止 SEGV 信號被觸發(使用 sigaddset)。 此外,(信號處理程序的)默認行為是在信號處理期間,相同的信號處理將被推遲,直到信號處理程序返回。 在 OP 代碼中,信號處理程序永遠不會返回(因為 siglongjmp)
這兩個問題都可以通過更改原始代碼來解決。
// Make sure all attributes are NULL.
struct sigaction action = {} ;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
// Not Needed:: sigaddset(&action.sa_mask, SIGSEGV);
// Add SA_NODEFER to disable the deferred processing of SIGSEGV.
action.sa_flags = SA_RESTART | SA_NODEFER ; /* Restart syscalls if possible */
// rest of code here
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.