本文轉自徐飛翔的“c語言運行時出現(xiàn)segment fault的原因”版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接和本聲明。
segment fault
段錯誤是在編程報錯中經(jīng)常出現(xiàn)的,特別是在c語言編程中,尤其常見,其原因本質(zhì)上上是訪問了非法(不屬于這個程序)的內(nèi)存地址空間,具體來說有以下幾種情況:
- 局部變量定義中,使用了過大的局部變量,大于了系統(tǒng)給之的棧(stack)的大小,因此報錯。比如以下代碼在linux環(huán)境下,就可能出現(xiàn)段錯誤報錯:
void foo(){ float vars[10000][10000]; }?
代碼很簡單,就是在棧上劃出了一個很大的連續(xù)內(nèi)存空間,翻譯成匯編如:
mov $100000016, %rsp # 還有多出的16個字節(jié)是上下文切換需要的內(nèi)存,frame pointer %rbp, return address等, # 同時如果用gcc等編譯的,還要考慮其內(nèi)存對齊的要求,即是其是16字節(jié)的倍數(shù)。?
這個棧大小可能超出了系統(tǒng)給定每個程序的棧的大小,可以通過shell命令
ulimit -s
進行查看系統(tǒng)給定的棧大小,比如筆者的就是:user@ubuntu: ulimit -s 8192?
注意這里都是以1024字節(jié)(1KB)為單位的,因此默認的就是8MB的棧大小,如果你的程序需要更大的棧空間,那么可以通過
ulimit -s 1000000?
類似這樣的命令去重定義最大的棧大小。
stack overflow
棧溢出 C語言是沒有對數(shù)組的邊界檢測的,這樣在實際應用中常常會導致越界的問題,我們知道,程序的棧如下圖所示:考察以下代碼:
void foo(){ int vars[100]; vars[100] = 0; vars[101] = 0; vars[102] = 0; vars[103] = 0; }?
當然,我們知道,我們對該數(shù)組
vars
只能檢索到vars[99]
,因為其索引范圍是[0,99]
,但是這種超出了理論上的索引邊界(越界)的“低級錯誤”確是在實際代碼中經(jīng)常出現(xiàn)的bug的根源之一。從上圖的程序棧我們可以看出,如果棧中的變量邊界溢出,那么可能會對一些上下文信息,比如return address進行期望之外的修改,導致難以預料的錯誤(比如無法返回到調(diào)用函數(shù),或者返回到不該返回的地址,這里容易被黑客進行棧溢出攻擊),因此操作系統(tǒng)一般會檢測這種段錯誤,同時報錯segment fault
。