[英]signal handling
我只是在Mac OS X中玩信號。
為什么在我的信號處理程序完成后,以下代碼不會產生SIGSEGV的默認行為? 在Linux下,代碼工作正常。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void err_crash();
void my_signal_handler (int signal)
{
fprintf(stderr, "signal == %i\n", signal);
fflush(stderr);
err_crash();
}
void err_crash()
{
static int count= 0;
if (count)
signal(SIGSEGV, SIG_DFL); /* break recursion loop if we recursed */
count++;
// one of the two should really crash ;)
((void)(*((int volatile *)NULL)));
*((int *)NULL) = 42;
abort(); /* in case we're not crashed yet... */
}
int main ()
{
signal(SIGSEGV, my_signal_handler);
err_crash();
return 0;
}
編輯:我得到的輸出如下:
bonecrusher:devel sw$ g++ signal_problems.cpp -o foo
bonecrusher:devel sw$ ./foo
signal == 11
^C
bonecrusher:devel sw$
問題是我希望程序在signal == 11
的輸出之后終止,但它永遠發生,我必須打斷它。
這實際上讓我大腦凍結了幾分鍾,而且在這個時代,人們不應該使用signal()
的原因只會在我身上變得更強。
首先,從signal()
的手冊頁
signal()的行為在UNIX版本中各不相同,並且在不同版本的Linux上也有不同的歷史變化。 避免使用:改為使用sigaction(2)。
進一步向下:
- 如果處置設置為函數,則首先將處置重置為SIG_DFL,或者阻止信號(參見下面的可移植性),然后使用參數signum調用處理程序。 如果處理程序的調用導致信號被阻塞,則在從處理程序返回時信號被解除阻塞。
在原來的Unix系統中,被安裝的處理程序時,配置被復位為SIG_DFL, 不阻斷的相同類型的輸入信號,然后將其跑處理函數。 System V提供了這個,而linux內核也是如此。
這意味着,一旦代碼在linux系統上運行,一旦調用第二個異常,它將直接退出。
現在到了有趣的部分。 BSD試圖改善這種行為。 再次從手冊頁:
在BSD上,當調用信號處理程序時,信號處理不會被重置,並且在處理程序執行時阻止信號的其他實例被傳遞。
由於mac osx部分基於BSD,一旦代碼在mac osx上運行,一旦調用第二個異常,它將處於掛起狀態並等待第一個異常的處理程序退出。 但既然你永遠不會退出,那你就陷入了僵局。
這就是為什么一個人應該使用sigaction()
而不是signal()
。
現在來一些提示:
處理程序應該簡短,並快速返回。 如果您正在執行計算並調用其他函數,那么您可能做錯了。 信號不能替代事件驅動的框架。
調用非異步安全的函數很糟糕。 考慮如果在調用fprintf
期間發生異常會發生什么,並且在處理程序內部再次調用fprintf
。 信號處理程序和程序數據都可能被破壞,因為它們在流本身上運行。
更多閱讀: “信號處理程序”中的“Do”和“Do not”
根據POSIX :
如果在阻塞時生成任何SIGFPE,SIGILL,SIGSEGV或SIGBUS信號,則結果是未定義的,除非信號由
kill()
函數,sigqueue()
函數或raise()
函數生成。
因為SIGSEGV在SIGSEGV信號處理程序中被阻塞,所以在這種情況下結果是未定義的,並且任何行為都是有效的。 如果您不希望它被阻止,您可以使用帶有SA_NODEFER
標志的sigaction()
安裝信號處理程序,或使用sigprocmask()
來取消阻塞信號處理程序中的信號。
在調試器中運行它並單步執行您希望崩潰的指令。
無法保證寫入無效地址必須創建分段錯誤。 也許Mac OS X會為您映射這些地址,而您正在覆蓋一些良性的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.