段錯(cuò)誤或段違規(guī)(segmentation violation)應(yīng)該已經(jīng)很清楚,,之前有過一篇文章介紹過"段模型"。
在一般硬件中,,段錯(cuò)誤是由于"內(nèi)存管理單元"(負(fù)責(zé)支持虛擬內(nèi)存的硬件)的異常所致,,而該異常則通常是由于解除引用一個(gè)未初始化或非法值的指針引起的。如果指針引用一個(gè)并不位于你的地址空間中的地址,,操作系統(tǒng)便會(huì)對(duì)此進(jìn)行干涉,。一個(gè)小型的會(huì)引起段錯(cuò)誤的程序如下: int *p = 0; *p = 17; //引起一個(gè)段錯(cuò)誤 一個(gè)微妙之處是,導(dǎo)致指針具有非法的值通常是由于不同的編程錯(cuò)誤所引起的,。和總線錯(cuò)誤不同,,段錯(cuò)誤更像是一個(gè)間接的癥狀而不是引起錯(cuò)誤的原因。 一個(gè)更糟糕的微妙之處是,,如果未初始化的指針恰好具有未對(duì)齊的值(對(duì)于指針?biāo)L問的數(shù)據(jù)而言),,它將會(huì)產(chǎn)生總線錯(cuò)誤,而不是段錯(cuò)誤,。對(duì)于絕大多數(shù)架構(gòu)的計(jì)算機(jī)而言確實(shí)如此,,因?yàn)镃PU先看到地址,然后再把它發(fā)送給MMU(內(nèi)存管理單元)。 通常導(dǎo)致段錯(cuò)誤的幾個(gè)直接原因: (1) 解除引用一個(gè)包含非法值的指針,; (2) 解除引用一個(gè)空指針(常常由于從系統(tǒng)程序中返回空指針,,并未經(jīng)檢查就使用)。 (3) 在未得到正確的權(quán)限時(shí)進(jìn)行訪問,。例如,,試圖往一個(gè)只寫的文本段存儲(chǔ)值就會(huì)引起段錯(cuò)誤。 (4) 用完了堆?;蚨芽臻g(虛擬內(nèi)存雖然巨大但絕非無(wú)限),。 下面這個(gè)說法可能過于簡(jiǎn)單,但在絕大多數(shù)架構(gòu)的絕大多數(shù)情況下,,總線錯(cuò)誤意味著CPU對(duì)進(jìn)程引用內(nèi)存的一些做法不滿,,而段錯(cuò)誤則是MMU對(duì)進(jìn)程引用內(nèi)存的一些情況發(fā)生抱怨。 以發(fā)生頻率為序,,最終可能導(dǎo)致段錯(cuò)誤的常見編程錯(cuò)誤是: 1. 壞指針值錯(cuò)誤:在指針賦值之前就用它來(lái)引用內(nèi)存,,或者向庫(kù)函數(shù)傳送一個(gè)壞指針(不要上當(dāng)!如果編譯器顯示系統(tǒng)程序中出現(xiàn)了段錯(cuò)誤,,并不是因?yàn)橄到y(tǒng)程序引起了段錯(cuò)誤,,問題很可能還在存在于自己的代碼中)。第三種可能導(dǎo)致壞指針的原因是對(duì)指針進(jìn)行釋放之后再訪問它的內(nèi)容,??梢孕薷膄ree語(yǔ)句,在指針釋放之后再將它置為空值,。 free(p); p = NULL; 這樣,,如果在指針釋放之后繼續(xù)使用該指針,至少程序能在終止之前進(jìn)行信息轉(zhuǎn)儲(chǔ),。 2. 改寫(overwrite)錯(cuò)誤:越過數(shù)組邊界寫入數(shù)據(jù),,在動(dòng)態(tài)分配的內(nèi)存兩端之外寫入數(shù)據(jù),或改寫一些堆管理數(shù)據(jù)結(jié)構(gòu)(在動(dòng)態(tài)分配的內(nèi)存之前的區(qū)域?qū)懭霐?shù)據(jù)就很容易發(fā)生這種情況),。 p = malloc(256); p[-1] = 0; p[256] = 0; 3. 指針釋放引起的錯(cuò)誤:釋放同一個(gè)內(nèi)存塊兩次,,或釋放一塊未曾使用malloc分配的內(nèi)存,或釋放仍在使用中的內(nèi)存,,或釋放一個(gè)無(wú)效的指針,。一個(gè)極為常見的與釋放內(nèi)存有關(guān)的錯(cuò)誤就是在 for(p=start; p; p=p->next)這樣的循環(huán)中迭代一個(gè)鏈表,并在循環(huán)體內(nèi)使用 free(p) 語(yǔ)句,。這樣,,在下一次循環(huán)迭代時(shí),程序就會(huì)對(duì)已經(jīng)釋放的指針進(jìn)行解除引用操作,,從而導(dǎo)致不可預(yù)料的結(jié)果,。 詳細(xì)出處參考:http://www./content-detail/238672.html |
|