c語言運行時出現segment fault的原因

segment fault段錯誤是在編程報錯中經常出現的,特別是在c語言編程中,尤其常見,其原因本質上上是訪問了非法(不屬於這個程序)的內存地址空間,具體來說有以下幾種情況:

  1. 局部變量定義中,使用了過大的局部變量,大於了系統給之的棧(stack)的大小,因此報錯。比如以下代碼在linux環境下,就可能出現段錯誤報錯:
void foo(){
	float vars[10000][10000];
}

代碼很簡單,就是在棧上劃出了一個很大的連續內存空間,翻譯成彙編如:

mov $100000016, %rsp
# 還有多出的16個字節是上下文切換需要的內存,frame pointer %rbp, return address等,
# 同時如果用gcc等編譯的,還要考慮其內存對齊的要求,即是其是16字節的倍數。

這個棧大小可能超出了系統給定每個程序的棧的大小,可以通過shell命令ulimit -s進行查看系統給定的棧大小,比如筆者的就是:

user@ubuntu: ulimit -s 
8192

注意這裏都是以1024字節(1KB)爲單位的,因此默認的就是8MB的棧大小,如果你的程序需要更大的棧空間,那麼可以通過

ulimit -s 1000000

類似這樣的命令去重定義最大的棧大小。

  1. stack overflow棧溢出
    C語言是沒有對數組的邊界檢測的,這樣在實際應用中常常會導致越界的問題,我們知道,程序的棧如下圖所示:

在這裏插入圖片描述

考察以下代碼:

void foo(){
	int vars[100];
	vars[100] = 0;
	vars[101] = 0;
	vars[102] = 0;
	vars[103] = 0;
}

當然,我們知道,我們對該數組vars只能檢索到vars[99],因爲其索引範圍是[0,99],但是這種超出了理論上的索引邊界(越界)的“低級錯誤”確是在實際代碼中經常出現的bug的根源之一。從上圖的程序棧我們可以看出,如果棧中的變量邊界溢出,那麼可能會對一些上下文信息,比如return address進行期望之外的修改,導致難以預料的錯誤(比如無法返回到調用函數,或者返回到不該返回的地址,這裏容易被黑客進行棧溢出攻擊),因此操作系統一般會檢測這種段錯誤,同時報錯segment fault

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章