您的代碼忽略了SIGSEGV而不是捕獲它。回想一下處理信號後,觸發信號的指令重新開始。在你的情況下,處理信號並沒有改變任何東西,所以在下一次嘗試違規指令時,它會以同樣的方式失敗。
如果您打算趕上信號改變這種
signal(SIGSEGV, SIG_IGN);
這個
signal(SIGSEGV, sighandler);
你或許應該還可以使用sigaction()
代替signal()
。請參閱相關手冊頁。
在你的情況下,有問題的指令是試圖取消引用NULL指針的指令。
printf("%d", *p);
以下內容完全取決於您的平臺。
您可以使用gdb
來確定什麼特定的彙編指令觸發信號。如果您的平臺是像我這樣的話,你會發現指令
movl (%rax), %esi
與RAX寄存器,保持0值,即NULL
。一種(不可移植的)方法可以在你的信號處理程序中解決這個問題,就是使用你的處理程序得到的第三個參數信號,即用戶上下文。下面是一個例子:
#include <signal.h>
#include <stdio.h>
#define __USE_GNU
#include <ucontext.h>
int *p = NULL;
int n = 100;
void sighandler(int signo, siginfo_t *si, ucontext_t* context)
{
printf("Handler executed for signal %d\n", signo);
context->uc_mcontext.gregs[REG_RAX] = &n;
}
int main(int argc,char ** argv)
{
signal(SIGSEGV, sighandler);
printf("%d\n", *p); // ... movl (%rax), %esi ...
return 0;
}
此程序將顯示:
Handler executed for signal 11
100
它首先導致通過嘗試取消引用NULL地址來執行該處理程序。然後處理程序通過設置rax到變量n
的地址來解決問題。一旦處理程序返回系統重試有問題的指令並且這次成功。 printf()
收到100作爲第二個參數。
雖然我強烈建議您不要在您的程序中使用這種非便攜式解決方案。
將會有一段時間,編寫代碼段會導致segfaults被認爲足以讓程序員入獄。 – 6502