來(lái)源:聚優(yōu)致成
一、什么是段錯(cuò)誤?一旦一個(gè)程序發(fā)生了越界訪問(wèn),cpu 就會(huì)產(chǎn)生相應(yīng)的保護(hù),于是 segmentation fault 就出現(xiàn)了,通過(guò)上面的解釋,段錯(cuò)誤應(yīng)該就是訪問(wèn)了不可訪問(wèn)的內(nèi)存。
這個(gè)內(nèi)存區(qū)要么是不存在的,要么是受到系統(tǒng)保護(hù)的,還有可能是缺少文件或者文件損壞。
二、段錯(cuò)誤產(chǎn)生的原因下面是一些典型的段錯(cuò)誤的原因:
非關(guān)聯(lián)化空指針——這是特殊情況由內(nèi)存管理硬件
試圖訪問(wèn)一個(gè)不存在的內(nèi)存地址(在進(jìn)程的地址空間)
試圖訪問(wèn)內(nèi)存的程序沒(méi)有權(quán)利(如內(nèi)核結(jié)構(gòu)流程上下文)
試圖寫(xiě)入只讀存儲(chǔ)器(如代碼段)
1、訪問(wèn)不存在的內(nèi)存地址
在C代碼,分割錯(cuò)誤通常發(fā)生由于指針的錯(cuò)誤使用,特別是在C動(dòng)態(tài)內(nèi)存分配。非關(guān)聯(lián)化一個(gè)空指針總是導(dǎo)致段錯(cuò)誤。
但野指針和懸空指針指向的內(nèi)存,可能會(huì)或可能不會(huì)存在,而且可能或不可能是可讀的還是可寫(xiě)的,因此會(huì)導(dǎo)致瞬態(tài)錯(cuò)誤。
#include 《stdio.h》int main (void){ int *ptr = NULL; *ptr = 0; return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
現(xiàn)在,非關(guān)聯(lián)化這些變量可能導(dǎo)致段錯(cuò)誤:非關(guān)聯(lián)化空指針通常會(huì)導(dǎo)致段錯(cuò)誤,閱讀時(shí)從野指針可能導(dǎo)致隨機(jī)數(shù)據(jù)但沒(méi)有段錯(cuò)誤,和閱讀從懸空指針可能導(dǎo)致有效數(shù)據(jù),然后隨機(jī)數(shù)據(jù)覆蓋。
2、訪問(wèn)系統(tǒng)保護(hù)的內(nèi)存地址
#include 《stdio.h》 int main (void){ int *ptr = (int *)0; *ptr = 100; return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
3、訪問(wèn)只讀的內(nèi)存地址
寫(xiě)入只讀存儲(chǔ)器提出了一個(gè) segmentation fault,這個(gè)發(fā)生在程序?qū)懭胱约旱囊徊糠执a段或者是只讀的數(shù)據(jù)段,這些都是由操作系統(tǒng)加載到只讀存儲(chǔ)器。
#include 《stdio.h》#include 《string.h》 int main (void){ char *ptr = “test”; strcpy (ptr, “TEST”); return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
#include 《stdio.h》 int main (void){ char *ptr = “hello”; *ptr = ‘H’; return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
上述例子ANSI C代碼通常會(huì)導(dǎo)致段錯(cuò)誤和內(nèi)存保護(hù)平臺(tái)。它試圖修改一個(gè)字符串文字,這是根據(jù)ANSI C標(biāo)準(zhǔn)未定義的行為。大多數(shù)編譯器在編譯時(shí)不會(huì)抓,而是編譯這個(gè)可執(zhí)行代碼,將崩潰。
包含這個(gè)代碼被編譯程序時(shí),字符串“hello”位于rodata部分程序的可執(zhí)行文件的只讀部分?jǐn)?shù)據(jù)段。
當(dāng)加載時(shí),操作系統(tǒng)與其他字符串和地方常數(shù)只讀段的內(nèi)存中的數(shù)據(jù)。當(dāng)執(zhí)行時(shí),一個(gè)變量 ptr 設(shè)置為指向字符串的位置,并試圖編寫(xiě)一個(gè)H字符通過(guò)變量進(jìn)入內(nèi)存,導(dǎo)致段錯(cuò)誤。
編譯程序的編譯器不檢查作業(yè)的只讀的位置在編譯時(shí),和運(yùn)行類unix操作系統(tǒng)產(chǎn)生以下運(yùn)行時(shí)發(fā)生 segmentation fault。
可以糾正這個(gè)代碼使用一個(gè)數(shù)組而不是一個(gè)字符指針,這個(gè)棧上分配內(nèi)存并初始化字符串的值:
#include 《stdio.h》 int main (void){ char ptr[] = “hello”; ptr[0] = ‘H’; return 0;}
即使不能修改字符串(相反,這在C標(biāo)準(zhǔn)未定義行為,在C char *類型,所以沒(méi)有隱式轉(zhuǎn)換原始代碼,在c++的 const char *類型,因此有一個(gè)隱式轉(zhuǎn)換,所以編譯器通常會(huì)抓住這個(gè)特定的錯(cuò)誤。
4、空指針廢棄
因?yàn)槭且粋€(gè)很常見(jiàn)的程序錯(cuò)誤空指針廢棄(讀或?qū)懺谝粋€(gè)空指針,用于C的意思是“沒(méi)有對(duì)象指針”作為一個(gè)錯(cuò)誤指示器),大多數(shù)操作系統(tǒng)內(nèi)存訪問(wèn)空指針的地址,這樣它會(huì)導(dǎo)致段錯(cuò)誤。
#include 《stdio.h》 int main (void){ int *ptr = NULL; printf (“%d\n”, *ptr); return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
這個(gè)示例代碼創(chuàng)建了一個(gè)空指針,然后試圖訪問(wèn)它的值(讀值)。在運(yùn)行時(shí)在許多操作系統(tǒng)中,這樣做會(huì)導(dǎo)致段錯(cuò)誤。
非關(guān)聯(lián)化一個(gè)空指針,然后分配(寫(xiě)一個(gè)值到一個(gè)不存在的目標(biāo))也通常會(huì)導(dǎo)致段錯(cuò)誤。
#include 《stdio.h》 int main (void){ int *ptr = NULL; *ptr = 1; return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
下面的代碼包含一個(gè)空指針,但當(dāng)編譯通常不會(huì)導(dǎo)致段錯(cuò)誤,值是未使用的。因此,廢棄通常會(huì)被優(yōu)化掉,死代碼消除。
#include 《stdio.h》 int main (void){ int *ptr = NULL; *ptr; return 0;}
還有,比如malloc 動(dòng)態(tài)分配內(nèi)存,釋放、置空完成后,不可再使用該指針。
#include 《stdio.h》#include 《stdlib.h》#include 《string.h》 int main(){ char* str=(char* )malloc(100); if(*str) { return; } strcpy(str,“hello”); printf(“%s\n”,str); free(str); str=NULL; strcpy(str,“abcdef”); return 0;}輸出結(jié)果:hello段錯(cuò)誤 (核心已轉(zhuǎn)儲(chǔ))
5、堆棧溢出
#include 《stdio.h》#include 《string.h》 int main (void){ main (); return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
上述例子的無(wú)限遞歸,導(dǎo)致的堆棧溢出會(huì)導(dǎo)致段錯(cuò)誤,但無(wú)線遞歸未必導(dǎo)致堆棧溢出,優(yōu)化執(zhí)行的編譯器和代碼的確切結(jié)構(gòu)。在這種情況下,遙不可及的代碼(返回語(yǔ)句)行為是未定義的。
因此,編譯器可以消除它,使用尾部調(diào)用優(yōu)化,可能導(dǎo)致沒(méi)有堆棧使用。其他優(yōu)化可能包括將遞歸轉(zhuǎn)換成迭代,給出例子的結(jié)構(gòu)功能永遠(yuǎn)會(huì)導(dǎo)致程序運(yùn)行,雖然可能不是其他堆棧溢出。
6、內(nèi)存越界(數(shù)組越界,變量類型不一致等)
#include 《stdio.h》int main (void){ char test[10]; printf (“%c\n”, test[100000]); return 0;}輸出結(jié)果:段錯(cuò)誤(核心已轉(zhuǎn)儲(chǔ))
-
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7605瀏覽量
136936 -
編程
+關(guān)注
關(guān)注
88文章
3616瀏覽量
93763
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論