版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
標(biāo)準(zhǔn)C語言段錯誤總結(jié)
C語言2009-02-1711:49:51閱讀21評論0字號:大中小訂閱
最近一段時間在linux下用C做一些學(xué)習(xí)和開發(fā),但是由于經(jīng)驗不足,問題多
多。而段錯誤就是讓我非常頭痛的一個問題。不過,目前寫幾百行的代碼,也很
少出現(xiàn)段錯誤,或者是即使出現(xiàn)了,也很容易找出來,并且處理掉。
那什么是段錯誤?段錯誤為什么是個麻煩事?以及怎么發(fā)現(xiàn)程序中的段
錯誤以及如何避免發(fā)生段錯誤呢?
一方面為了給自己的學(xué)習(xí)做個總結(jié),另一方面由于至今沒有找到一個比
較全面介紹這個雖然是“FREQUENTLYASKEDQUESTIONS”的問題,所以我來做個
拋磚引玉吧。下面就從上面的幾個問題出發(fā)來探討一下“Segmentationfaults”
吧。
目錄
lo什么是段錯誤?
2O為什么段錯誤這么“麻煩”?
3。編程中通常碰到段錯誤的地方有哪些?
4。如何發(fā)現(xiàn)程序中的段錯誤并處理掉?
正文
lo什么是段錯誤?
下面是來自Answers,com的定義:
Asegmentationfault(oftenshortenedtosegfault)isaparticularerror
conditionthatcanoccurduringtheoperationofcomputersoftware.In
short,asegmentationfaultoccurswhenaprogramattemptstoaccessa
memorylocationthatitisnotallowedtoaccess,orattemptstoaccess
amemorylocationinawaythatisnotallowed(e.g.,attemptstowrite
toaread-onlylocation,ortooverwritepartoftheoperating
system).SystemsbasedonprocessorsliketheMotorola68000tendtorefer
totheseeventsasAddressorBuserrors.
Segmentationisoneapproachtomemorymanagementandprotectioninthe
operatingsystem.Ithasbeensupersededbypagingformostpurposes,but
muchoftheterminologyofsegmentationisstillused,''segmentation
fault〃beinganexample.Someoperatingsystemsstillhavesegmentation
atsomelogicallevelalthoughpagingisusedasthemainmemorymanagement
policy.
OnUnix-likeoperatingsystems,aprocessthataccessesinvalidmemory
receivestheSIGSEGVsignal.OnMicrosoftWindows,aprocessthataccesses
invalidmemoryreceivestheSTATUSACCESSVIOLATIONexception.
Asegmentationfault(oftenshortenedtosegfault)isaparticularerror
conditionthatcanoccurduringtheoperationofcomputersoftware.In
short,asegmentationfaultoccurswhenaprogramattemptstoaccessa
memorylocationthatitisnotallowedtoaccess,orattemptstoaccess
amemorylocationinawaythatisnotallowed(e.g.,attemptstowrite
toaread-onlylocation,ortooverwritepartoftheoperatingsystem).
SystemsbasedonprocessorsliketheMotorola68000tendtorefertothese
eventsasAddressorBuserrors.
Segmentationisoneapproachtomemorymanagementandprotectioninthe
operatingsystem.Ithasbeensupersededbypagingformostpurposes,but
muchoftheterminologyofsegmentationisstillused,segmentation
fault"beinganexample.Someoperatingsystemsstillhavesegmentation
atsomelogicallevelalthoughpagingisusedasthemainmemorymanagement
policy.
OnUnix-likeoperatingsystems,aprocessthataccessesinvalidmemory
receivestheSIGSEGVsignal.OnMicrosoftWindows,aprocessthataccesses
invalidmemoryreceivestheSTATUS_ACCESS_V1OLAT1ONexception.
另外,這里有個基本上對照的中文解釋,來自
httpi/A^vw./html_sql/3/132559.htm
所謂的段錯誤就是指訪問的內(nèi)存超出了系統(tǒng)所給這個程序的內(nèi)存空間,通常這
個值是由gdtr來保存的,他是一個48位的寄存器,其中的32位是保存由它指
向的gdl表,后13位保存相應(yīng)于gdl的下標(biāo),最后3位包括了程序是否在內(nèi)存
中以及程序的在epu中的運行級別,指向的gdt是由以64位為一個單位的表,在
這張表中就保存著程序運行的代碼段以及數(shù)據(jù)段的起始地址以及與此相應(yīng)的段
限和頁面交換還有程序運行級別還有內(nèi)存粒度等等的信息。?旦?個程序發(fā)生了
越界訪問,epu就會產(chǎn)生相應(yīng)的異常保護(hù),于是segmentationfault就出現(xiàn)了
所謂的段錯誤就是指訪問的內(nèi)存超出了系統(tǒng)所給這個程序的內(nèi)存空間,通常這個
值是由gdtr來保存的,他是一個48位的寄存器,其中的32位是保存由它指向
的gdt表,后13位保存相應(yīng)于gdt的下標(biāo),最后3位包括了程序是否在內(nèi)存中
以及程序的在epu中的運行級別,指向的gdt是由以64位為一個單位的表,在這
張表中就保存著程序運行的代碼段以及數(shù)據(jù)段的起始地址以及與此相應(yīng)的段限
和頁面交換還有程序運行級別還有內(nèi)存粒度等等的信息。一日.一個程序發(fā)牛了越
界訪問,cpu就會產(chǎn)生相應(yīng)的異常保護(hù),于是segmentationfault就出現(xiàn)了
通過上面的解釋,段錯誤應(yīng)該就是訪問了不可訪問的內(nèi)存,這個內(nèi)存區(qū)要么是
不存在的,要么是受到系統(tǒng)保護(hù)的。
2o為什么段錯誤這么麻煩?
中國linux論壇有一篇精華帖子《Segmentfault之永遠(yuǎn)的痛》
(http:〃www.linuxforum.net/forum/gshowflat.php?Cat=&Board=program&Num
bcr=193239&pagc=2&vicw=collapsed&sb=5&o=all&fpart=l&vc=l)
在主題帖子里頭,作者這么寫道:
寫程序好多年了,Segnentfault是許多C程序員頭疼的提不。指針是好東西,
但是隨著指針的使用卻誕生了這個同樣威力巨大的惡魔。
Segmentfault之所以能夠流行于世,是與Glibc庫中基本所有的函數(shù)都默認(rèn)型
參指針為非空有著密切關(guān)系的。
不知道什么時候才可以有能夠處理NULL的glibc庫誕生啊!
不得已,我現(xiàn)在為好多的函數(shù)做了衣服,避免glibc的函數(shù)被NULL給感染,導(dǎo)
致我的Mem訪問錯誤,而我還不知道NULL這個病毒已經(jīng)在侵蝕我的身體了。
Segmentfault永遠(yuǎn)的痛
寫程序好多年了,Segnentfault是許多C程序員頭疼的提示“指針是好東西,
但是隨著指針的使用卻誕生了這個同樣威力巨大的惡魔。
Segmentfault之所以能夠流行于世,是與G1ibc庫中基本所有的函數(shù)都默認(rèn)型
參指針為非空有著密切關(guān)系的。
不知道什么時候才可以有能夠處理NULL的glibc庫誕生啊!
不得已,我現(xiàn)在為好多的函數(shù)做了衣服,避免glibc的函數(shù)被NULL給感染,導(dǎo)
致我的Mem訪問錯誤,而我還不知道NULL這個病毒已經(jīng)在侵蝕我的身體了。
Segmentfault永遠(yuǎn)的痛
寫程序好多年了,Segnentfault是許多C程序員頭疼的提示。指針是好東西,
但是隨著指針的使用卻誕生了這個同樣威力巨大的惡魔。
Segmentfault之所以能夠流行于世,是與Glibc庫中基本所有的函數(shù)都默認(rèn)型
參指針為非空有著密切關(guān)系的。
不知道什么時候才可以有能夠處理NULL的glibc庫誕生?。?/p>
不得已,我現(xiàn)在為好多的函數(shù)做了衣服,避免glibc的函數(shù)被NULL給感染,導(dǎo)
致我的Mem訪問錯誤,而我還不知道NULL這個病毒已經(jīng)在侵蝕我的身體了。
Segmentfault永遠(yuǎn)的痛
后面有好多網(wǎng)友都跟帖了,討論了Segmentationfaults為什么這么
“痛”,尤其是對于服務(wù)器程序來說,是非常頭痛的,為了提高效率,要盡量減
少一些不必要的段錯誤的“判斷和處理”,但是不檢查又可能會存在段錯誤的隱
患。
那么如何處理這個“麻煩”呢?
就像人不可能“完美”一樣,由人創(chuàng)造的“計算機(jī)語言“同樣沒有“完美”
的解決辦法。
我們更好的解決辦法也許是:
通過學(xué)習(xí)前人的經(jīng)驗和開發(fā)的工具,不斷的嘗試和研究,找出更恰當(dāng)?shù)?/p>
方法來避免、發(fā)現(xiàn)并處理它。對于一些常見的地方,我們可以避免,對于一些“隱
藏”的地方,我們要發(fā)現(xiàn)它,發(fā)現(xiàn)以后就要及時處理,避免留下隱患。
下面我們可以通過具體的實驗來舉出一些經(jīng)常出現(xiàn)段錯誤的地方,然后
再舉例子來發(fā)現(xiàn)和找出這類錯誤藏身之處,最后處理掉。
3。編程中通常碰到段錯誤的地方有哪些?
為了進(jìn)行下面的實驗,我們需要準(zhǔn)備兩個工具,一個是g",一個是gdb
我是在ubuntu下做的實驗,安裝這兩個東西是比較簡單的
sudoapt-getinstallgcc-4.0libc6-dev
sudoapt-getinstallgdb
好了,開始進(jìn)入我們的實驗,我們粗略的分一下類
1)往受到系統(tǒng)保護(hù)的內(nèi)存地址寫數(shù)據(jù)
有些內(nèi)存是內(nèi)核占用的或者是其他程序正在使用,為了保證系統(tǒng)正常工
作,所以會受到系統(tǒng)的保護(hù),而不能任意訪問。
例子1:
Code:
#include<stdio.h>
intmainO
(
inti=0;
scanfi);/*shouldhaveused&i*/
printf(〃%d\rT,i);
return0;
)
[Ctrl+ASelectAll]
編譯和執(zhí)行一下
$gcc-osegerrsegerr.c
$./segerr
10
段錯誤
咋一看,好像沒有問題哦,不就是讀取一個數(shù)據(jù)然后給輸出來嗎?
下面我們來調(diào)試一下,看看是什么原因?
$gcc-g-osegerrsegerr.c-加-g選項杳看調(diào)試信息
$gdb./segerr
(gdb)1-用1(list)顯示我們的源代碼
1ttinclude<stdio.h>
2
3int
4mainC
5(
6inti=0;
7
8scanf(〃%d〃,i);/*shouldhaveused&i
*/
9printf(〃%d\n〃,i);
10return0;
(gdb)b8一用b(break)設(shè)置斷點
Breakpoint1at0x80483b7:filesegerr.c,line8.
(gdb)pi-用p(print)打印變量i的值[看到
沒,這里i的值是0哦]
$1=0
(gdb)r一用r(run)運行,直到斷點處
Startingprogram:/home/falcon/temp/segerr
Breakpoint1,main;)atsegerr.c:8
8scanf(〃%d〃,i);/*shouldhaveused&i
*/一[試圖往地址0處寫進(jìn)一個值]
(gdb)n一用n(next)執(zhí)行下一步
10
ProgramreceivedsignalSIGSEGV,Segmentationfault.
0xb7e9alcain_I0_vfscanf()from/lib/tls/i686/cmov/libc.so.6
(gdb)c一在上面我們接收到了SIGSEGV,然后用
c(continue)繼續(xù)執(zhí)行
Continuing.
ProgramterminatedwithsignalSTGSEGV,Segmentationfault.
Theprogramnolongerexists.
(gdb)quit一退出gdb
$gcc-g-osegerrsegerr.c-加-g選項查看調(diào)試信息
$gdb./segerr
(gdb)1-用1(list)顯示我們的源代碼
1#include<stdio.h>
2
3int
4main(}
5(
6inti=0:
7
8scanfi);/*shouldhaveused&i
*/
9printf(〃%d\n〃,i);
10return0;
(gdb)b8一用b(break)設(shè)置斷點
Breakpoint1at0x80483b7:filesegerr.c,line8.
(gdb)pi一用p(print)打印變量i的值[看到
沒,這里i的值是。哦]
$1=0
(gdb)r一用r(run)運行,直到斷點處
Startingprogram:/home/falcon/temp/segerr
Breakpoint1,main:)atsegerr.c:8
8scanf(〃%d",i);/*shouldhaveused&i
*/~[試圖往地址0處寫進(jìn)一個值]
(gdb)n一用n(next)執(zhí)行下?步
10
ProgramreceivedsignalSIGSEGV,Segmentationfault.
0xb7e9alcain_I0vfscanf()from/lib/tls/i686/cmov/libc.so.6
(gdb)c一在上面我們接收到了SIGSEGV,然后用
c(coniinue)繼續(xù)執(zhí)行
Continuing.
ProgramterminatedwithsignalSICSECV,Segmentationfault.
Theprogramnolongerexists.
(gdb)quit-退出gdb
果然
我們“不小心”把&i寫成了i
而我們剛開始初始化了i為0,這樣我們不是試圖向內(nèi)存地址0存放一個值嗎?
實際上很多情況下,你即使沒有初始化為零,默認(rèn)也可能是0,所以要特別注
-ZdKa
,導(dǎo)、O
補(bǔ)充:
可以通過man7signal查看SIGSEGV的信息。
$man7signal|grepSEGV
Reformattingsignal;7),pleasewait...
SIGSEGV11CoreInvalid
memoryreference
例子2:
Code:
#include<stdio.h>
intmain()
(
char*p;
p=NULL;
*P二'x';
printfC%c/z,*p);
return0;
)
[Ctrl+ASelectAll]
很容易發(fā)現(xiàn),這個例子也是試圖往內(nèi)存地址0處寫東西。
這里我們通過gdb來查看段錯誤所在的行
$gcc-g-osegerrsegerr.c
$gdb./segerr
(gdb)r一直接運行,我們看到拋出段錯誤以后,自動顯示出了
出現(xiàn)段錯誤的行,這就是一個找出段錯誤的方法
Startingprogram:/home/falcon/temp/segerr
ProgramreceivedsignalS1GSEGV,Segmentationfault.
0x08048516inmain:)atsegerr.c:10
10*p='x';
(gdb)
$gcc-g-osegerrsegerr.c
$gdb./segerr
(gdb)r一直接運行,我們看到拋出段錯誤以后,自動顯示出了
出現(xiàn)段錯誤的行,這就是一個找出段錯誤的方法
Startingprogram:/home/falcon/temp/segerr
ProgramreceivedsignalSIGSEGV,Segmentationfault.
0x08048516inmain;)atsegerr.c:10
10*p='x';
(gdb)
2
)內(nèi)存越界(數(shù)組越界,變量類型不?致等)
例子3:
Code:
tfinclude<stdio.h>
intmain()
(
chartest[1];
printf(z/%cz/,test[1000000000]);
return0;
)
[Ctrl+ASelectAll]
這里是比較極端的例子,但是有時候可能是會出現(xiàn)的,是個明顯的數(shù)組越界的
問題
或者是這個地址是根本就不存在的
例子4:
Code:
#include<stdio.h>
intmain()
(
intb=10;
printf(〃%s\n〃,b);
return0;
}
[Ctrl+ASelectAll]
我們試圖把一個整數(shù)按照字符串的方式輸出出去,這是什么問題呢?
由于還不熟悉調(diào)試動態(tài)鏈接庫,所以
我只是找到了printf的源代碼的這里
聲明部分:
intpos=0,cnt_printed_chars=0,i;
unsignedchar*chptr;
va_listap;
%$格式控制部分:
case's':
chptr=va_arg(ap,unsignedchar*);
i=0;
while(chptr[i])
{...
cnt_printed_chars++;
putchar(chptr[i++]);
}
聲明部分:
intpos=0,cnt_printed_chars=0,i;
unsignedchar*chptr;
valistap;
如格式控制部分:
case's':
chptr=va_arg(ap,unsignedchar*);
i=0;
while(chptr[i])
{...
entprintedchars++;
putchar(chptr[i++]);
仔細(xì)看看,發(fā)現(xiàn)了這樣一個問題,在打印字符串的時候,實際上是打印某個地
址開始的所有字符,但是當(dāng)你想把整數(shù)當(dāng)字符串打印的時候,這個整數(shù)被當(dāng)成
了一個地址,然后printf從這個地址開始去打印字符,直到某個位置上的值為
\0。所以,如果這個整數(shù)代表的地址不存在或者不可訪問,自然也是訪問了不該
訪問的內(nèi)存segmentationfault。
類似的,還有諸如:sprintf等的格式控制問題
比如,試圖把char型或者是int的按照版輸出或存放起來,如:
Code:
#include<stdio.h>
ttinclude<string.h>
charc-c;
inti=10;
charbuf[100];
printfCW;c);〃試圖把char型按照字符串格式輸出,這里
的字符會解釋成整數(shù),再解釋成地址,所以原因同上面那個例子
printf(〃%s〃,i);〃試圖把int型按照字符串輸出
mcmset(buf,0,100):
sprintf(buf,z/%s\c);〃試圖把char型按照字符串格式轉(zhuǎn)換
memset(buf,0,100):
sprintf(buf,i);〃試圖把int型按照字符串轉(zhuǎn)換
[Ctrl+ASelectAll]
3)其他
其實大概的原因都是一樣的,就是段錯誤的定義。但是更多的容易出錯的地方就
要自己不斷積累,不段發(fā)現(xiàn),或者吸納前人已經(jīng)積累的經(jīng)驗,并且注意避免再
次發(fā)生。
例如:
<1>定義了指針后記得初始化,在使用的時候記得判斷是否為NULL
<2>在使用數(shù)組的時候是否被初始化,數(shù)組下標(biāo)是否越界,數(shù)組元素是否存在等
<3>在變量處理的時候變量的格式控制是否合理等
再舉一個比較不錯的例子:
我在進(jìn)行一個多線程編程的例子里頭,定義了一個線程數(shù)組
ftdefineTHREAD_MAX_NUM
pthread_tthread[THREAD_MAX_NUM];
用pthread_create創(chuàng)建了各個線程,然后用pthread_join來等待線程的結(jié)束
剛開始我就直接等待,在創(chuàng)建線程都成功的時候,pthreadjoin能夠順利等待
各個線程結(jié)束,但是一旦創(chuàng)建線程失敗,那用pthread.join來等待那個本不存
在的線程時自然會存在訪問不能訪問的內(nèi)存的情況,從而導(dǎo)致段錯誤的發(fā)生,
后來,通過不斷調(diào)試和思考,并且得到網(wǎng)絡(luò)上資料的幫助,找到了上面的原因
和解決辦法:
在創(chuàng)建線程之前,先初始化我們的線程數(shù)組,在等待線程的結(jié)束的時候,判斷
線程是否為我們的初始值
如果是的話,說明我們的線程并沒有創(chuàng)建成功,所以就不能等拉。否則就會存在
釋放那些并不存在或者不可訪問的內(nèi)存空間。
上面給出了很常見的幾種出現(xiàn)段錯誤的地方,這樣在遇到它們的時候就容易避
免拉。但是人有時候肯定也會有疏忽的,甚至可能還是會經(jīng)常出現(xiàn)上面的問題或
者其他常見的問題,所以對于一些大型一點的程序,如何跟蹤并找到程序中的
段錯誤位置就是需要掌握的一門技巧拉。
4。如何發(fā)現(xiàn)程序中的段錯誤?
有個網(wǎng)友對這個做了比較全面的總結(jié),除了感謝他外,我把地址弄了過來。文章
名字叫《段錯誤bug的調(diào)試》
(http:〃www.cublog.cn/u/5251/showart.php?id=173718),應(yīng)該說是很全面的。
而我常用的調(diào)試方法有:
1)在程序內(nèi)部的關(guān)鍵部位輸出(printf)信息,那樣可以跟蹤段錯誤在代碼中
可能的位置
為了方便使用這種調(diào)試方法,可以用條件編譯指令#ifdefDEBUG和#0。近£毛
printf函數(shù)給包含起天,編譯的時候加上-DDEBUG參數(shù)就可以查看調(diào)試信息。反
之,不加上該參數(shù)進(jìn)行調(diào)試就可以。
2)用gdb來調(diào)試,在運行到段錯誤的地方,會自動停下來并顯示出錯的行和行
號
這個應(yīng)該是很常用的,如果需要用gdb調(diào)試,記得在編譯的時候加上-g參數(shù),
用來顯示調(diào)試信息,對于這個,網(wǎng)友在《段錯誤bug的調(diào)試》文章里創(chuàng)造性的使
用這樣的方法,使得我們在執(zhí)行程序的時候就可以動態(tài)撲獲段錯誤可能出現(xiàn)的
位置:通過撲獲SIGSEGV信號來觸發(fā)系統(tǒng)調(diào)用gdb來輸出調(diào)試信息。如果加上上
面提到的條件編譯,那我們就可以非常方便的進(jìn)行段錯誤的調(diào)試?yán)?/p>
3)還有—?個catchscgv命令
通過查看幫助信息,可以看到
Catchsegmentationfaultsinprograms
這個東西就是用來撲獲段錯誤的,它通過動態(tài)加載器(Id-linux.so)的預(yù)加載
機(jī)制(PRELOAD)把一個事先寫好的庫(/lib/libSegFault.so)加載上,用于捕
捉斷錯誤的出錯信息。
到這里,“初級總結(jié)篇”算是差不多完成拉。歡迎指出其中表達(dá)不當(dāng)甚至錯誤的
地方,先謝過!
參考資料[具體地址在上面的文章中都已經(jīng)給出拉]:
lo段錯誤的定義
Anscrs.com
http:〃www.answers,com
Definitionof"Segmentationfault"
http:〃www.faqs.org/qa/qa-673.html
2o《什么是段錯誤》
http://www.Iinux999.org/html_sql/3/132559.htm
3。《Segmentfault之永遠(yuǎn)的痛》
http:〃www.linuxforum.net/forum/gshowflat.php?Cat=&Board=program&Numb
er=193239&page=2&view=collapsed&sb=5&o=all&fpart=
4?!抖五e誤bug的調(diào)試》
http:〃www.cublog.cn/u/5251/showart.php?id=173718
后記
雖然感覺沒有寫什么東西,但是包括查找資料和打字,也花了好些幾個小時,不
過總結(jié)一下也是值得的,歡迎和我一起交流和討論,也歡迎對文章中表達(dá)不當(dāng)
甚至是錯誤的地方指正一下
段錯誤(Segmentalionfault)
原文出處:/blog/article.php7tid_700.html
我只是把排版弄舒服一點,很好的文章,雖然說是初級篇,但幫助確實很大。
I)往受到系統(tǒng)保護(hù)的內(nèi)存地址寫數(shù)據(jù)
有些內(nèi)存定內(nèi)核占用的或者是其他程序正在使用,為了保證系統(tǒng)正常工作,所以會受到系統(tǒng)的保護(hù),而不
能任意訪問.
#include<stdio.h>
int
main()
(
inti=0;
scanf("%d",i);/*shouldhaveused&i*/
printf("%d\n",i);
return0:
)
編譯和執(zhí)行一下,咋一看,好像沒有問題哦,不就是讀取一個數(shù)據(jù)然后給輸出來嗎?
falcon@falcon:-/ieinpSgcc-g-osegerrsegerr.c-力口-g選項查看調(diào)試信息
falcon@falcon:~/tempSgdb./segerr
GNUgdb6.4-dcbian
Copyright2005FreeSoftwareFoundation,Inc.
GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare
welcometochangeitand/ordistributecopiesofitundercertainconditions.
Type“showcopying“toseetheconditions.
ThereisabsolutelynowarrantyforGDB.Type44showwananty"tordetails.
ThisGDBwasconfiguredas44i486-linux-gnu"…Usinghostlibthrcad_dblibrary"/
lib/tls/i686/cmov/libthread_db.so.1".
(gdb)1-用l(lisl)顯示我們的源代碼
1#include<stdio.h>
2
3int
4main()
5(
6inti=0;
7
8scanfi);/*shouldhaveused&i*/
9printf(”\心i);
10return0;
(gdb)b8-用b(break)設(shè)置斷點
Breakpoint1at0x80483b7:filesegerr.c,line8.
(gdb)pi-用p(print)打印變量i的值[看到?jīng)].這里i的值是0哦]
$1=0
(gdb)1?-用r(run)運行,直到斷點處
Starlingprogram:/homc/falcon/temp/segcrr
Breakpoint1.main()atsegen.c:8
8scanf("%d”,i);/*shouldhaveused&i*/■[試圖往地址0處寫進(jìn)一個值]
(gdb)n-用n(nexl)執(zhí)行下一步
10
ProgramreceivedsignalSIGSEGV.Segmentationfault.
0xb7e9alcain_10_vfscanf()from/Iib/tis/i686/cmov/libc.so.6
(gdb)c-在上面我們接收到了SIGSEGV,然后用c(continue)繼續(xù)執(zhí)行
Continuing.
ProgramterminatedwithsignalSIGSEGV.Segmentationfault.
Theprogramnolongerexists.
(gdb)quit-退出gdb
果然
我們“不小心”把&i寫成了i
而我們剛開始初始化了i為0,這樣我們不是試圖向內(nèi)存地址0存放一個值嗎?
[補(bǔ)充:
可以通過man7signal查看SIGSEGV的信息。
falcon@falcon:~/tempSman7signal|grepSEGV
Reformattingsignal(7),pleasev/ait...
SIGSEGV11CoreInvalidmemoryreference
例子2:
#include<stdio.h>
int
main()
1
char*p;
p=NULL;
*p='x';
printf(',%c,\*p);
return0:
}
很容易發(fā)現(xiàn),這個例子也是試圖往內(nèi)存地址0處寫東西。
這里我們通過gdb來查看段錯誤所在的行
falcon@falcon>/tempSgcc-g-osegerrsegerr.c
falcon@falcon:~/tenipSgdb./s3geiT
GNUgdb6.4-dcbian
Copyright2005FreeSoftwareFoundation,Inc.
GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare
welcometochangeitand/ordistributecopiesofitundercertainconditions.
Type“showcopying''toseetheconditions.
ThereisabsolutelynowarrantyforGDB.Type44showwarranty"fordetails.
ThisGDBwasconfiguredasUi486-linux-gnu",,,Usinghostlibthread_dblibrary
<</lib/tls/i686/cmo\7libthread_dbso.r,.
(gdb)r-直接運行,我們看到拋出段錯誤以后,自動顯示出了出現(xiàn)段錯誤的行,這就是一個找出段錯誤的
方法
Startingprogram:/home/falcon/temp/segerr
ProgramreceivedsignalSIGSEGV,Segmentationfault.
0x08048516inmain()atseger.c:10
10*p=&';
(gdb)
2)內(nèi)存越界(數(shù)組越界,變量類型不?致等)
#include<stdio.h>
int
main()
(
chartest[l];
prinlf('%c'',test[1000000000));
return0;
}
這里是比較極端的例子,但是有時候可能是會出現(xiàn)的.是個明顯的數(shù)組越界的問題
或者是這個地址是根本就不存在的
例子4:
#include<stdio.h>
int
niain()
{
intb=10;
printff*%s\n”,b);
return0;
}
我們試圖把一個整數(shù)按照字符串的方式輸出出去,這是什么問題呢?
由于還不熟悉調(diào)試動態(tài)鏈接庫.所以
我只是找到了printf的源代碼的這里
聲明部分:
intpos=0,cnt_printed_chars=0.i;
unsignedchar*chplr;
va_listap;
/*%s格式控制部分:*/
ease's':
chpir=va_arg(apunsignedchar*);
i=0;
while(chptr|iJ)
{???
cnt_printed_chars++;
putchar(chptr[i++]);
}
由于我沒有仔細(xì)分析代碼,大致的原因也可能是地址越界的原因?不過我可不確定哦。
如果大家知道怎么調(diào)試printf函數(shù),麻煩幫忙找出越界的真正原因吧,這個段錯誤也可能是
處在va_slart和va_arg等函數(shù)里頭?或者直接看看這個這里的prinlf源代碼的分析,看看是否
可以找出出錯的地方:
/bbsdetail_47325.htrnl
類似的,還有諸如:sprintf等的格式控制問題
比如,試圖把char型或者是ini的按照%s輸出或存放起來,如:
#include<stdio.h>
#include<string.h>
charc='c';
inti=10;
charbuf]IOO];
printf("%s",c);〃試圖把char型按照字符串格式輸出
printf("%s",i);〃試圖把int型按照字符串輸出
memset(buf,0,100);
叩rinlf(buf,"%s”,c);〃試圖把char型按照字符串格式轉(zhuǎn)換
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 生物信息學(xué)分析IBD癌變的關(guān)鍵調(diào)控基因
- 保險行業(yè)數(shù)據(jù)分析師的答案解析
- 物業(yè)管理師國家職業(yè)資格考試復(fù)習(xí)含答案
- 深度解析(2026)《GBT 19448.3-2004圓柱柄刀夾 第3部分裝徑向矩形車刀的B型刀夾》
- 辦公室文員工作考核標(biāo)準(zhǔn)及辦法
- 瓣膜介入器械的麻醉配合策略
- 環(huán)保組織招聘環(huán)保項目活動策劃與執(zhí)行專員面試題及答案
- 網(wǎng)絡(luò)安全專家面試題及攻防實戰(zhàn)案例含答案
- 剪床項目可行性分析報告范文(總投資7000萬元)
- 寬容和感恩的培訓(xùn)
- 廣東省汕頭市金平區(qū)2024-2025學(xué)年七年級上學(xué)期期末考試數(shù)學(xué)試題
- 過敏性休克的搶救流程
- 常用機(jī)床電氣檢修課件 課題十一 T612 型臥式鏜床電氣檢修
- 全國人大機(jī)關(guān)直屬事業(yè)單位2026年度公開招聘工作人員考試模擬卷帶答案解析
- 云肩非遺模板
- 頭頸部腫瘤介紹
- 安全監(jiān)理工作總程序
- 2026年中國宏觀經(jīng)濟(jì)展望分析報告:底部夯實亮點引領(lǐng)未來方向
- 2025年新型健康飲品研發(fā)可行性研究報告及總結(jié)分析
- 竣工決算業(yè)務(wù)合同范本
評論
0/150
提交評論