Segmentation fault in Linux
段錯誤應該就是訪問了不可訪問的內存,這個內存要么是不存在的,要么是受系統保護的。
- SIGSEGV是在訪問內存時發生的錯誤,它屬於內存管理的范疇
- SIGSEGV是一個用戶態的概念,是操作系統在用戶態程序錯誤訪問內存時所做出的處理
- 當用戶態程序訪問(訪問表示讀、寫或執行)不允許訪問的內存時,產生SIGSEGV
- 當用戶態程序以錯誤的方式訪問允許訪問的內存時,產生SIGSEGV
用戶態程序地址空間,特指程序可以訪問的地址空間范圍。如果廣義的說,一個進程的地址空間應該包括內核空間部分,只是它不能訪問而已。
SIGSEGV產生的可能情況
SIGSEGV在很多時候是由於指針越界引起的,但並不是所有的指針越界都會引發SIGSEGV。一個越界的指針,如果不引用它,是不會引起SIGSEGV的。而即使引用了一個越界的指針,也不一定引起SIGSEGV。
錯誤的訪問類型引起
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* ch = "hello world";
ch[1] = 'H';
return 0;
}
上述程序編譯沒有問題,但是運行時彈出SIGSEGV。此例中,”hello world”作為一個常量字符串,在編譯后會被放在.rodata
節(GCC),最后鏈接生成目標程序時.rodata
節會被合並到text segment與代碼段放在一起,故其所處內存區域是只讀的。這就是錯誤的訪問類型引起的SIGSEGV。
訪問了不屬於進程地址空間的內存
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)0xC0000fff;
*p = 10;
return 0;
}
還有一種可能,往受到系統保護的內存地址寫數據,最常見的就是給一個指針以0地址:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i = 0;
scanf ("%d", i); /* should be used &i */
printf ("%d\n", i);
return 0;
}
訪問了不存在的內存
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = NULL;
*p = 1;
return 0;
}
在實際情況中,此例中的空指針可能指向用戶態地址空間,但其所指向的頁面實際不存在。
內存越界,數組越界,變量類型不一致等
#include <stdio.h>
#include <stdlib.h>
int main()
{
char test[1];
printf("%c", test[10]);
return 0;
}
試圖把一個整數按照字符串的方式輸出
#include <stdio.h>
#include <stdlib.h>
int main()
{
int b = 10;
printf("%s\n", b);
return 0;
}