在linux c/c++中捕獲段錯誤
關於段錯誤
所謂的段錯誤就是指訪問的記憶體超出了系統所給這個程式的記憶體空間,在程式設計中幾類做法容易導致段錯誤,基本上是錯誤地使用指標引起的。
1) 訪問系統資料區,尤其是往系統保護的記憶體位址寫資料最常見就是給乙個指標以0位址。
2) 記憶體越界(陣列越界,變數型別不一致等):訪問到不屬於你的記憶體區域。
解決方法:我們在用c/c++語言寫程式的時候,記憶體管理的絕大部分工作都是需要我們來做的。實際上,記憶體管理是乙個比較繁瑣的工作,無論你多高明,經驗多豐富,難免會在此處犯些小錯誤,而通常這些錯誤又是那麼的淺顯而易於消除。但是手工「除蟲」(debug),往往是效率低下且讓人厭煩的,本文將就"段錯誤"這個記憶體訪問越界的錯誤談談如何快速定位這些"段錯誤"的語句。
抓住段錯誤
在linux中,程式在進行異常的記憶體操作後,會發出乙個sigsegv 訊號,我們只需要捕獲到這個訊號就可以對段錯誤進行後期處理。
如何處理、定位段錯誤
發生段錯誤時的函式呼叫關係體現在棧幀上,可以通過在訊號處理函式中呼叫 backstrace 來獲取棧幀資訊,
void onsigsegv(int signum, siginfo_t *info,void *ptr)
void * array[25]; /* 25 層,太夠了 : ),你也可以自己設定個其他值 */
int nsize = backtrace(array, sizeof(array)/sizeof(array[0]));
for (int i=nsize-3; i>=2; i--)else{
printf("signal[%d] catchedwhen running code at unknown address\n", signum);
通過以上兩種方式輸出的都是關於堆疊位址,對編譯原理不熟悉的人是不會分析的,此時我們就需要借助工具來進行分析了,當讓,如果你的輸出程式不包含除錯資訊則不會準確的輸出段錯誤位置,要保證我們的程式編譯選項包含-g這個選項。當讓,資深的程式設計師只需要得到段錯誤的堆疊資訊就基本能分析出出錯位置了。畢竟我們都是新手,需要借助工具。
addr2line 這個工具是linux平台下用來將位址資訊轉換為行號等資訊的,當把位址轉換到行號後就能找到出錯位置啦。這個時候就可以認真分析**了。
例如:lib***.so 在maps 中輸入為
40018000-40019000 rw-p 00000000 00:09 17255/mnt/hgfs/share/net/tcpbreak/lib***.so
可以看到,此庫在動態載入時的開始位址為 0x40018000
假如通過上訴方法定位到位址 0x4001824b
那麼實際上在靜態檔案中的偏移為 0x4001800 – 0x4001824b = 0x24b
於是我們通過addr2line 24b -s -c -f -e lib***.so
就會定位到實際的出錯位址了。
關於在鍊錶中的段錯誤
如若在 合併鍊錶並去除重複元素 的執行語句 while p3 data p1 data p1 p1 p1 next while p3 data p2 data p2 p2 p2 next 用來跳過鍊錶l1 l2中與新建的鍊錶重複的元素,注意如果這麼寫的話可能會出現 段錯誤 當p1跳到null的時候進...
在 docker 容器中捕獲訊號
訊號是一種程序間通訊的形式。乙個訊號就是核心傳送給程序的乙個訊息,告訴程序發生了某種事件。當乙個訊號被傳送給乙個程序後,程序會立即中斷當前的執行流並開始執行訊號的處理程式。如果沒有為這個訊號指定處理程式,就執行預設的處理程式。程序需要為自己感興趣的訊號註冊處理程式,比如為了能讓程式優雅的退出 接到退...
在 docker 容器中捕獲訊號
訊號是一種程序間通訊的形式。乙個訊號就是核心傳送給程序的乙個訊息,告訴程序發生了某種事件。當乙個訊號被傳送給乙個程序後,程序會立即中斷當前的執行流並開始執行訊號的處理程式 這麼說不太準確,訊號是在特定的時機被處理 如果沒有為這個訊號指定處理程式,就執行預設的處理程式。程序需要為自己感興趣的訊號註冊處...