国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

程序異常分析指南

2019-11-06 07:24:55
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

http://www.cnblogs.com/fanzhidongyzby/p/6503080.html

linux上編寫運(yùn)行C語(yǔ)言程序,經(jīng)常會(huì)遇到程序崩潰、卡死等異常的情況。程序崩潰時(shí)最常見的就是程序運(yùn)行終止,報(bào)告Segmentation fault (core dumped)錯(cuò)誤。而程序卡死一般來(lái)源于代碼邏輯的缺陷,導(dǎo)致了死循環(huán)、死鎖等問(wèn)題。總的來(lái)看,常見的程序異常問(wèn)題一般可以分為非法內(nèi)存訪問(wèn)資源訪問(wèn)沖突兩大類。

非法內(nèi)存訪問(wèn)(讀/寫):非法指針、多線程共享數(shù)據(jù)訪問(wèn)沖突、內(nèi)存訪問(wèn)越界、緩沖區(qū)溢出等。資源訪問(wèn)沖突:棧內(nèi)存溢出、堆內(nèi)存溢出、死鎖等。

一、非法內(nèi)存訪問(wèn)

非法內(nèi)存訪問(wèn)是最常見的程序異樣原因,可能開發(fā)者看的“表象”不盡相同,但是很多情況下都是由于非法內(nèi)存訪問(wèn)引起的。

1. 非法指針

非法指針是最典型的非法內(nèi)存訪問(wèn)案例,空指針、指向非法地址的指針是代碼中最常出現(xiàn)的錯(cuò)誤。

示例代碼如下:

long *ptr; *ptr = 0; // 空指針 ptr = (long *)0x12345678; *ptr = 100; // 非法地址訪問(wèn)

無(wú)論是訪問(wèn)地址為0的空指針,還是用戶態(tài)無(wú)效的地址,都會(huì)導(dǎo)致非法指針訪問(wèn)錯(cuò)誤。實(shí)際編程過(guò)程中,強(qiáng)制類型轉(zhuǎn)換一不小心就會(huì)產(chǎn)生非法指針,因此做強(qiáng)制類型轉(zhuǎn)換時(shí)要格外注意,最好事先做好類型檢查,以避免該問(wèn)題。

2. 多線程共享數(shù)據(jù)訪問(wèn)沖突

在多線程程序中,非法指針的產(chǎn)生可能就沒那么容易發(fā)現(xiàn)了。一般情況下,多個(gè)線程對(duì)共享的數(shù)據(jù)同時(shí)寫,或者一寫多讀時(shí),如果不加鎖保證共享數(shù)據(jù)的同步訪問(wèn),則會(huì)很容易導(dǎo)致數(shù)據(jù)訪問(wèn)沖突,繼而引發(fā)非法指針、產(chǎn)生錯(cuò)誤數(shù)據(jù),甚至影響執(zhí)行邏輯。

示例代碼如下:

// 全局變量 long *ptr = (long *)malloc(sizeof(long)); // 線程1 if (ptr) { *ptr = 100; // 潛在的非法地址訪問(wèn) } // 線程2 free(ptr); ptr = NULL;

上述代碼中,全局初始化了指針ptr,線程1會(huì)判斷該指針不為NULL時(shí)進(jìn)行寫100操作,而線程2會(huì)釋放ptr指向的內(nèi)存,并將ptr置為NULL。雖然線程1做了判斷處理,但是多線程環(huán)境下,則會(huì)出現(xiàn)線程2剛調(diào)用完free操作,還未來(lái)得及將ptr設(shè)為NULL時(shí),發(fā)生線程上下文切換,轉(zhuǎn)而執(zhí)行線程1的寫100操作,從而引發(fā)非法地址訪問(wèn)。

解決并發(fā)數(shù)據(jù)訪問(wèn)沖突的方案是使用鎖同步線程。針對(duì)圖中的線程同步問(wèn)題,只需要在線程1和線程2的處理邏輯前,使用讀寫鎖同步即可。操作系統(tǒng)或者gcc的庫(kù)函數(shù)內(nèi)也存在很多線程不安全的API,在使用這些API時(shí),一定要仔細(xì)閱讀相關(guān)的API文檔,使用線程鎖進(jìn)行同步訪問(wèn)。

3. 內(nèi)存訪問(wèn)越界

內(nèi)存訪問(wèn)越界經(jīng)常出現(xiàn)在對(duì)數(shù)組處理的過(guò)程中。本身C語(yǔ)言并未有對(duì)數(shù)組邊界的檢查機(jī)制,因此在越界訪問(wèn)數(shù)組內(nèi)存時(shí)并不一定會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤,但是因?yàn)樵浇缭L問(wèn)繼而引發(fā)的連鎖反應(yīng)就無(wú)法避免了。

示例代碼如下:

void out_of_bound() { long *ptr; long buffer[] = {0}; ptr = buffer; buffer[1] = 0; // 越界訪問(wèn)導(dǎo)致ptr被覆蓋 ptr[0]++; }

示例代碼在函數(shù)out_of_bound內(nèi)定義了兩個(gè)變量:指針ptr和數(shù)組buffer。指針ptr指向buffer其實(shí)地址,正常情況下使用ptr[0]可以訪問(wèn)訪問(wèn)到buffer的第一個(gè)元素。然而對(duì)buffer[1]的越界寫操作會(huì)直接覆蓋ptr的值為0,從而導(dǎo)致ptr為空指針。

了解該問(wèn)題的原因需要清楚局部變量在棧內(nèi)的存儲(chǔ)機(jī)制。在函數(shù)調(diào)用時(shí),會(huì)將調(diào)用信息、局部變量等保存在進(jìn)程的棧內(nèi)。棧是從高地址到低地址增長(zhǎng)的,因此先定義的局部變量的地址一般大于后定義的局部變量地址。上述代碼中,buffer和ptr的大小都是8Byte,因此buffer[1]實(shí)際就是ptr所在的內(nèi)存。這樣對(duì)buffer[1]的寫操作會(huì)覆蓋ptr的值就不足為怪了。總之,對(duì)數(shù)組訪問(wèn)的時(shí)候,做好邊界檢查是重中之重。類似的問(wèn)題也出現(xiàn)在對(duì)字符串的操作中,包括gcc提供的字符串庫(kù)函數(shù)也存在該問(wèn)題,使用時(shí)需要尤其注意。

說(shuō)到邊界檢查,這里引申出一個(gè)話題。在對(duì)數(shù)組處理時(shí),經(jīng)常會(huì)遇到逆序遍歷數(shù)組后n-1個(gè)元素的情況,有些時(shí)候一不小心就會(huì)這樣實(shí)現(xiàn)代碼:

void backScanArray(long buffer[]) { for(unsigned int index = sizeof(buffer) / sizeof(long) - 1; index > 0; index--) { PRintf("%ld/n", buffer[index]); } }

乍一看,代碼邏輯幾乎沒什么問(wèn)題,可是一旦buffer長(zhǎng)度為0時(shí),就會(huì)觸發(fā)死循環(huán)了。舉出這個(gè)極端的例子主要是為了說(shuō)明數(shù)組邊界檢查時(shí)要格外小心。

4. 緩沖區(qū)溢出

緩沖區(qū)溢出攻擊是系統(tǒng)安全領(lǐng)域常見的話題,其本質(zhì)還是數(shù)組越界訪問(wèn)的一個(gè)特殊例子。為了方便討論,這里仍舉緩沖區(qū)在棧內(nèi)存的例子。(緩沖區(qū)溢出攻擊也可以發(fā)生的堆內(nèi)存中,感興趣的讀者可閱讀《0day安全軟件漏洞分析技術(shù)》一書)

我們?nèi)允褂玫谌?jié)的示例代碼,不過(guò)修改了一個(gè)字符:

void stack_over_flow() { long *ptr; long buffer[] = {0}; ptr = buffer; buffer[3] = 0; // 緩沖區(qū)溢出攻擊 ptr[0]++; }

雖然只是修改了一個(gè)字符,但是行為已經(jīng)和之前的代碼完全不同了。實(shí)際在函數(shù)調(diào)用時(shí),棧內(nèi)不止保存了局部變量,還包括調(diào)用參數(shù)、調(diào)用后返回地址、調(diào)用前的rbp(棧基址寄存器)的值,俗稱棧幀。

隨著buffer越界的索引不斷增大,可以覆蓋的信息可以越來(lái)越多,甚至是上級(jí)調(diào)用的函數(shù)棧幀信息都可以被覆蓋。修改buffer[3]的值意味著stack_over_flow函數(shù)調(diào)用返回后,會(huì)跳轉(zhuǎn)到buffer[3]的值對(duì)應(yīng)的地址上執(zhí)行,而這個(gè)地址是0,程序會(huì)直接崩潰。試想如果將該值設(shè)置為一個(gè)惡意的代碼入口地址,那么就意味著潛在的巨大系統(tǒng)安全風(fēng)險(xiǎn)。緩沖求溢出攻擊的具體操作方式其實(shí)更復(fù)雜,這里只是描述了其基本思想,感興趣的讀者可以參考我之前的博文《緩沖區(qū)溢出攻擊》。

二、資源訪問(wèn)沖突

1. 棧內(nèi)存溢出

此處的棧內(nèi)存溢出和前邊討論的棧內(nèi)緩沖區(qū)溢出并不是同一個(gè)概念。操作系統(tǒng)為每個(gè)進(jìn)程分配的最大的棧內(nèi)存大小是有最大上限的,因此當(dāng)函數(shù)的局部變量的大小超過(guò)一定大小后(考慮到進(jìn)程本身使用了部分棧內(nèi)存),進(jìn)程的棧內(nèi)存便不夠使用了,于是就發(fā)生了溢出。

通過(guò)Linux命令可以查看當(dāng)前系統(tǒng)設(shè)置的進(jìn)程最大棧大小(單位:KB):

$ ulimit -s8192

如果函數(shù)內(nèi)申請(qǐng)的數(shù)組大小超過(guò)該值(實(shí)際上比該值略小),則會(huì)引發(fā)棧內(nèi)存溢出異常。

另一種觸發(fā)棧內(nèi)存溢出的方式是左遞歸(無(wú)限遞歸):

void left_recursive() { left_recursive();}

由于每次函數(shù)調(diào)用都會(huì)開辟新棧幀保存函數(shù)調(diào)用信息,而左遞歸邏輯上是不會(huì)終止的,因此總有進(jìn)程棧內(nèi)存被耗盡的時(shí)候,屆時(shí)便發(fā)生了棧內(nèi)存溢出。

2. 堆內(nèi)存溢出

堆內(nèi)存溢出與棧內(nèi)存溢出是同一類概念,不過(guò)進(jìn)程堆空間的大小上限,因?yàn)椴僮飨到y(tǒng)的分頁(yè)機(jī)制,理論上只受限于機(jī)器位長(zhǎng),即便物理內(nèi)存和swap分區(qū)大小不足,也可以通過(guò)操作系統(tǒng)的配置進(jìn)行擴(kuò)展。鑒于堆內(nèi)存大小的這些性質(zhì),一般的程序不太容易觸發(fā)堆內(nèi)存溢出異常。但是長(zhǎng)期駐留內(nèi)存的服務(wù)器進(jìn)程,如果因?yàn)槌绦蜻壿嫷娜毕荩瑢?dǎo)致程序的部分內(nèi)存一直申請(qǐng),而得不到釋放的話,久而久之,就會(huì)觸發(fā)堆內(nèi)存溢出,從而進(jìn)程被操作系統(tǒng)強(qiáng)制kill掉,這就是常說(shuō)的內(nèi)存泄漏問(wèn)題。

C語(yǔ)言使用malloc/free盡享堆內(nèi)存的申請(qǐng)和釋放,開發(fā)者編寫程序時(shí),必須小心翼翼地控制這兩對(duì)函數(shù)的調(diào)用邏輯,以防申請(qǐng)和釋放不對(duì)等誘發(fā)內(nèi)存泄漏問(wèn)題。而實(shí)際開發(fā)過(guò)程中,人工保證這樣的準(zhǔn)確性是十分困難的,后邊我們會(huì)介紹如何使用分析工具幫我們排查程序中潛在的內(nèi)存漏洞問(wèn)題。

3. 死鎖

前面講到,為了解決多線程共享數(shù)據(jù)訪問(wèn)沖突的問(wèn)題,需要使用線程鎖同步線程的執(zhí)行邏輯。而對(duì)鎖的不正當(dāng)使用,同樣會(huì)產(chǎn)生程序異常,即死鎖。死鎖不會(huì)導(dǎo)致前邊所述的直接導(dǎo)致程序崩潰的異常,而是會(huì)掛起進(jìn)程的線程,從而導(dǎo)致程序的部分任務(wù)卡死,不能提供正常的服務(wù)。

最典型的死鎖產(chǎn)生方式,就是熟知的ABBA鎖。

圖中仍使用兩個(gè)線程作為示例,假設(shè)線程1在申請(qǐng)完A鎖后,發(fā)生了上下文切換執(zhí)行線程2,線程2申請(qǐng)B鎖成功后,再去申請(qǐng)A鎖就會(huì)失敗,從而導(dǎo)致線程2掛起。此時(shí),上下文即便再次切換到線程1,線程1也無(wú)法成功申請(qǐng)到B鎖,從而線程1也會(huì)掛起。這樣,線程1和2都無(wú)法成功申請(qǐng)到自己想要的鎖,也無(wú)法釋放自己已經(jīng)申請(qǐng)到的鎖給其他其他線程使用,從而導(dǎo)致死鎖。

解決此類死鎖的辦法就是讓每個(gè)線程申請(qǐng)鎖時(shí)是批量申請(qǐng),要么一次性全部申請(qǐng)成功,要么一次性都不申請(qǐng)。還有一種辦法就是提前預(yù)知該情況的發(fā)生,不使用兩個(gè)鎖同步線程,這就需要人工費(fèi)力地排查潛在的死鎖可能,當(dāng)然,也有分析工具幫助開發(fā)者完成此類工作,稍后會(huì)作介紹。

三、程序異常解決方法

前面提到的程序異常類型,除了死循環(huán)和死鎖導(dǎo)致進(jìn)程卡死之外,其他的異常都會(huì)導(dǎo)致進(jìn)程崩潰,觸發(fā)Segmentation fault (core dumped)錯(cuò)誤。Linux操作系統(tǒng)提供了允許程序core dumped時(shí)生成core dumped文件紀(jì)錄程序崩潰時(shí)的“進(jìn)程快照”,以供開發(fā)者分析程序的出錯(cuò)行為和原因,使用gdb就可以調(diào)試分析core dumped文件。而對(duì)于內(nèi)存泄漏和死鎖,開源工具Valgrind提供了相關(guān)的分析功能(Valgrind也提供了大量的內(nèi)存監(jiān)測(cè)工具,可以和core dumped文件分析互補(bǔ)使用)。至于死循環(huán)可以通過(guò)gdb直接調(diào)試跟蹤解決,這里不再贅述。

1. CoreDumped異常分析

step 1:

讓程序運(yùn)行崩潰時(shí)生成core dumped文件,需要對(duì)操作系統(tǒng)進(jìn)行簡(jiǎn)單的配置。

$ sudo ulimit -c unlimited$ sudo echo core > /proc/sys/kernel/core_pattern

第一條命令是打開系統(tǒng)core dumped文件生成開關(guān),第二條命令是將進(jìn)程崩潰時(shí)生成的core dumped文件放在程序執(zhí)行目錄下,并以core作為文件名前綴。

step 2:

接下來(lái),以內(nèi)存訪問(wèn)越界的例子作為示例,完整代碼如下,源文件名為main.c。

void out_of_bound() { long *ptr; long buffer[] = {0}; ptr = buffer; buffer[1] = 0; // 越界訪問(wèn)導(dǎo)致ptr被覆蓋 ptr[0]++; } void main() { out_of_bound(); }

step 3:

編譯運(yùn)行main.c,編譯時(shí)使用需要使用-g選項(xiàng),保留可執(zhí)行文件調(diào)試信息,方便后續(xù)分析。

$ gcc main.c -o main -g$ ./mainSegmentation fault (core dumped)$ ls core.*core.9251

我們看到程序崩潰后,生成了core dumped文件core.9251,其中9251為程序運(yùn)行時(shí)進(jìn)程的pid。

step 4:

調(diào)試core dumped文件。

$ gdb main core.9251./x: line 4: 9251 Segmentation fault (core dumped) ./mainReading symbols from demo...done.[New LWP 9251][Thread debugging using libthread_db enabled]Using host libthread_db library "/usr/lib/libthread_db.so.1".Core was generated by `./main'.Program terminated with signal SIGSEGV, Segmentation fault.#0 0x00000000004004d6 in out_of_bound () at main.c:66 ptr[0]++;(gdb) backtrace#0 0x00000000004004d6 in out_of_bound () at main.c:6#1 0x00000000004004f5 in main () at main.c:10(gdb) print ptr$1 = (long *) 0x0(gdb)

gdb輸出了程序崩潰時(shí)代碼的執(zhí)行位置,main.c文件的第6行。使用backtrace命令可以打印當(dāng)時(shí)的函數(shù)調(diào)用棧信息,以方便定位出錯(cuò)的上層調(diào)用邏輯。使用print命令打印ptr指針的值,確實(shí)為0,與我們之前的討論一致。上面分析僅僅是一個(gè)非常簡(jiǎn)單的示例,實(shí)際開發(fā)過(guò)程中遇到的出錯(cuò)位置可能更隱蔽,甚至是庫(kù)函數(shù)的二進(jìn)制代碼,屆時(shí)需要根據(jù)個(gè)人經(jīng)驗(yàn)來(lái)具體問(wèn)題具體分析了。

2. 使用Valgrind進(jìn)行內(nèi)存泄漏和死鎖檢測(cè)

Valgrind是非常強(qiáng)大的內(nèi)存調(diào)試、內(nèi)存泄漏檢測(cè)以及性能分析工具,它可以模擬執(zhí)行用戶二進(jìn)制程序,幫助用戶分析潛在的內(nèi)存泄漏和死鎖的可能邏輯。

step 1:

開源工具Valgrind提供了源碼tar包,需要下載、編譯、安裝使用(最新版本Valgrind如果編譯報(bào)錯(cuò),請(qǐng)將gcc更新到最新版本)。

$ wget http://valgrind.org/downloads/valgrind-3.12.0.tar.bz2$ tar xf valgrind-3.12.0.tar.bz2$ cd valgrind-3.12.0$ ./configure --prefix=/usr/local/$ make && sudo make install$ valgrind --versionvalgrind-3.12.0

step 2:

準(zhǔn)備內(nèi)存泄漏示例代碼。

#include <stdlib.h>void main() { malloc(4);}

step 3:

使用Valgrind進(jìn)行內(nèi)存檢測(cè)。

$ valgrind --tool=memcheck --leak-check=full ./main ==24470== Memcheck, a memory error detector==24470== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.==24470== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info==24470== Command: ./main==24470== ==24470== ==24470== HEAP SUMMARY:==24470== in use at exit: 4 bytes in 1 blocks==24470== total heap usage: 1 allocs, 0 frees, 4 bytes allocated==24470== ==24470== LEAK SUMMARY:==24470== definitely lost: 0 bytes in 0 blocks==24470== indirectly lost: 0 bytes in 0 blocks==24470== possibly lost: 0 bytes in 0 blocks==24470== still reachable: 4 bytes in 1 blocks==24470== suppressed: 0 bytes in 0 blocks==24470== Reachable blocks (those to which a pointer was found) are not shown.==24470== To see them, rerun with: --leak-check=full --show-leak-kinds=all==24470== ==24470== For counts of detected and suppressed errors, rerun with: -v==24470== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

我們看到LEAK SUMMARY節(jié)內(nèi)容中顯示程序退出時(shí),仍有4B的內(nèi)存可以訪問(wèn),也就是產(chǎn)生了內(nèi)存泄漏。

step 4:

準(zhǔn)備死鎖示例代碼,我們實(shí)現(xiàn)了前面討論的ABBA鎖的代碼。

#include <stdlib.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t lock_A = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t lock_B = PTHREAD_MUTEX_INITIALIZER; void *run1(void *args) { pthread_mutex_lock(&lock_A); sleep(1); pthread_mutex_lock(&lock_B); pthread_mutex_unlock(&lock_B); pthread_mutex_unlock(&lock_A); }void *run2(void *args){ pthread_mutex_lock(&lock_B); sleep(1); pthread_mutex_lock(&lock_A); pthread_mutex_unlock(&lock_A); pthread_mutex_unlock(&lock_B); } void main(){ pthread_t tid[2]; if (pthread_create(&tid[0], NULL, &run1, NULL) != 0) { exit(1); } if (pthread_create(&tid[1], NULL, &run2, NULL) != 0) { exit(1); } pthread_join(tid[0], NULL); pthread_join(tid[1], NULL); pthread_mutex_destroy(&lock_A); pthread_mutex_destroy(&lock_B);}

step 5:

編譯(需要鏈接pthread庫(kù)),并使用Valgrind進(jìn)行死鎖檢測(cè)。

$ gcc main.c -o main -g -lpthread$ valgrind --tool=helgrind ./main==24652== Helgrind, a thread error detector==24652== Copyright (C) 2007-2015, and GNU GPL'd, by OpenWorks LLP et al.==24652== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info==24652== Command: ./main==24652== Ctrl + C==24652== ==24652== Process terminating with default action of signal 2 (SIGINT)==24652== at 0x4E4568D: pthread_join (in /usr/lib/libpthread-2.24.so)==24652== by 0x4C2EAA7: pthread_join_WRK (hg_intercepts.c:553)==24652== by 0x4C32908: pthread_join (hg_intercepts.c:572)==24652== by 0x400806: main (main.c:39)==24652== ---Thread-Announcement------------------------------------------==24652== ==24652== Thread #2 was created==24652== at 0x51427AE: clone (in /usr/lib/libc-2.24.so)==24652== by 0x4E431A9: create_thread (in /usr/lib/libpthread-2.24.so)==24652== by 0x4E44C12: pthread_create@@GLIBC_2.2.5 (in /usr/lib/libpthread-2.24.so)==24652== by 0x4C31810: pthread_create_WRK (hg_intercepts.c:427)==24652== by 0x4C328FD: pthread_create@* (hg_intercepts.c:460)==24652== by 0x4007BA: main (main.c:30)==24652== ==24652== ----------------------------------------------------------------==24652== ==24652== Thread #2: Exiting thread still holds 1 lock==24652== at 0x4E4CF1C: __lll_lock_wait (in /usr/lib/libpthread-2.24.so)==24652== by 0x4E46B44: pthread_mutex_lock (in /usr/lib/libpthread-2.24.so)==24652== by 0x4C2EE18: mutex_lock_WRK (hg_intercepts.c:894)==24652== by 0x4C32CE1: pthread_mutex_lock (hg_intercepts.c:917)==24652== by 0x40073F: run1 (main.c:12)==24652== by 0x4C31A04: mythread_wrapper (hg_intercepts.c:389)==24652== by 0x4E44453: start_thread (in /usr/lib/libpthread-2.24.so)==24652== ==24652== ---Thread-Announcement------------------------------------------==24652== ==24652== Thread #3 was created==24652== at 0x51427AE: clone (in /usr/lib/libc-2.24.so)==24652== by 0x4E431A9: create_thread (in /usr/lib/libpthread-2.24.so)==24652== by 0x4E44C12: pthread_create@@GLIBC_2.2.5 (in /usr/lib/libpthread-2.24.so)==24652== by 0x4C31810: pthread_create_WRK (hg_intercepts.c:427)==24652== by 0x4C328FD: pthread_create@* (hg_intercepts.c:460)==24652== by 0x4007E7: main (main.c:34)==24652== ==24652== ----------------------------------------------------------------==24652== ==24652== Thread #3: Exiting thread still holds 1 lock==24652== at 0x4E4CF1C: __lll_lock_wait (in /usr/lib/libpthread-2.24.so)==24652== by 0x4E46B44: pthread_mutex_lock (in /usr/lib/libpthread-2.24.so)==24652== by 0x4C2EE18: mutex_lock_WRK (hg_intercepts.c:894)==24652== by 0x4C32CE1: pthread_mutex_lock (hg_intercepts.c:917)==24652== by 0x400780: run2 (main.c:21)==24652== by 0x4C31A04: mythread_wrapper (hg_intercepts.c:389)==24652== by 0x4E44453: start_thread (in /usr/lib/libpthread-2.24.so)==24652== ==24652== ==24652== For counts of detected and suppressed errors, rerun with: -v==24652== Use --history-level=approx or =none to gain increased speed, at==24652== the cost of reduced accuracy of conflicting-access information==24652== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)

第8行日志,程序因?yàn)樗梨i卡死,使用Ctrl+C強(qiáng)制退出。第27和48顯示:線程2和3(主線程編號(hào)為1)在退出時(shí)仍然格持有1個(gè)鎖,很明顯,這兩個(gè)線程相互死鎖了,與之前的討論一致。

總結(jié)

本文從Linux上C語(yǔ)言編程中遇到的異常開始討論,將異常大致分為非法內(nèi)存訪問(wèn)和資源訪問(wèn)沖突兩大類,并對(duì)每類典型的案例做了解釋和說(shuō)明,最后通過(guò)core dumped文件分析和Valgrind工具的測(cè)試,給讀者提供了遇到程序運(yùn)行時(shí)異常時(shí)的解決方案。希望看到此文的讀者,在以后遇到程序異常時(shí)都能泰然自若,冷靜分析,順利地找到問(wèn)題的根源,便不枉費(fèi)筆者撰寫此文之心血。

參考資料

coredump簡(jiǎn)介與coredump原因總結(jié):http://blog.csdn.net/newnewman80/article/details/8173770C語(yǔ)言申請(qǐng)內(nèi)存時(shí)堆棧大小限制:http://blog.csdn.net/xxxxxx91116/article/details/10068555Linux malloc大內(nèi)存的方法: http://www.cfanz.cn/index.php?c=article&a=read&id=103888valgrind 的使用簡(jiǎn)介:http://blog.csdn.net/sduliulun/article/details/7732906一個(gè) Linux 上分析死鎖的簡(jiǎn)單方法:http://www.ibm.com/developerworks/cn/linux/l-cn-deadlock/
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 滨州市| 巢湖市| 汉中市| 泰和县| 胶州市| 旬邑县| 大石桥市| 千阳县| 太原市| 赤壁市| 连州市| 汤原县| 靖安县| 延庆县| 浏阳市| 昌邑市| 旬邑县| 金寨县| 美姑县| 娱乐| 衡东县| 佛坪县| 靖边县| 黄大仙区| 磐安县| 泸溪县| 黄平县| 会宁县| 汾阳市| 门头沟区| 台中县| 镇宁| 榆林市| 延津县| 左云县| 渑池县| 吉安县| 溆浦县| 樟树市| 孝义市| 敦化市|