1. 程式人生 > 其它 >segment fault 段錯誤 (core dumped)的起因分析(轉)

segment fault 段錯誤 (core dumped)的起因分析(轉)

核心使用記憶體描述符結構體表示程序的地址空間,該結構體包含了和程序地址空間有關的全部資訊。記憶體描述符由mm_struct結構體表示,定義在檔案<linux/sched.h>中。程序地址空間由每個程序的線性地址區(vm_area_struct)組成。通過核心,程序可以給自己的地址空間動態的新增或減少線性區域。

mm_users域記錄正在使用該地址的程序數目。比如,如果兩個程序共享該地址空間,那麼mm_users的值便等於2;mm_count域是mm_struct的結構體的主引用計數,只要 mm_users不為0,那麼mm_count值就等於1.當mm_users值減為0(兩個執行緒都退出)時,mm_count域的值才變為0。如果mm_count的值等於0,說明已經沒有任何指向該mm_struct結構 體的引用了,這時該結構體會被銷燬。mmap和mm_rb這兩個不同的資料結構描述的物件是相同的:該地址空間中的全部記憶體區域。

而fork系統呼叫產生的子程序中的mm_struct結構體實際是通過檔案kernel/fork.c中的alloc_mm()巨集從mm_cachep slab快取中分配得到的。通常,每個程序都有一個唯一的 mm_struct結構體,即唯一的程序地址空間。是否共享地址空間,幾乎是程序和Linux中所謂執行緒間本質上的唯一區別。

程序就是通過mm_struct 來描述3G的線性地址空間,mm_struct通過

劃分為一個個線性區,而每個線性區用一個 vm_area_struct來描述,其實我們的mm_struct是與我們的可執行檔案的結構體相關聯的,首先看我們的mm_struct:

從上面可以看出mm_struct 包含了程序start_code,end_code,start_data,end_data等section段描述的結構,我們來看一個可執行檔案的構成來看看,就拿上面的hello

[qiqi@localhost test]$ objdump -h hello

hello: file format elf32-i386

Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000013 08048134 08048134 00000134 2**0

VMA代表虛擬地址,這裡表示我們的程式執行是的虛擬地址起為 0x08048134

  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048148  08048148
00000148 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA ...... 10 .init 00000030 080482f4 080482f4 000002f4 2**2 init載入頭最開始執行的 CONTENTS, ALLOC, LOAD, READONLY, CODE 11 .plt 00000070 08048324 08048324 00000324 2**2 跳轉我們程式執行的頭 CONTENTS, ALLOC, LOAD, READONLY, CODE 12 .text 000001cc 080483a0 080483a0 000003a0 2**4 ..即我們的程式碼段 CONTENTS, ALLOC, LOAD, READONLY, CODE 13 .fini 0000001c 0804856c 0804856c 0000056c 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 14 .rodata 00000018 08048588 08048588 00000588 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA .... 20 .dynamic 000000c8 08049654 08049654 00000654 2**2 CONTENTS, ALLOC, LOAD, DATA 21 .got 00000004 0804971c 0804971c 0000071c 2**2 CONTENTS, ALLOC, LOAD, DATA .... 23 .data 00000004 08049744 08049744 00000744 2**2 資料段 CONTENTS, ALLOC, LOAD, DATA 24 .bss 00000008 08049748 08049748 00000748 2**2 未初始化段 ALLOC 25 .comment 0000002c 00000000 00000000 00000748 2**0 未初始化的符號表 CONTENTS, READONLY

由連結過程可以看出main並不是真正的入口,是從.plt段中跳轉過來的所有的程式都是從這裡進入的,有一相當於jmp *main的跳轉指令,

同時可以看出我們的可執行檔案被分成以一個不同的section,這就和我們mm_struct中的線性區描述符對應起來了,比如我們的.data段就被載入到start_data與end_data地址空間的地方,其它的段與此類似!!!!!!,

那麼為什麼我們產生segment fault 呢,???因為我們訪問的地址沒有對映啊,!!!就是地址沒有在mm_struct中描述的空間中,因為我們的

mm_struct並沒有對映整個3G的空間啊,因為我們程式的每個段都是有大小限制的,.data,.text,.bss,.common等已經指名的section以外,

還有兩個非常重要的線性區start_stack,end_stack(棧)與start_brk,end_brk(堆),如果我們訪問的線性地址沒有在這些地址空間中,那麼就會產生segment fault,



造成程式core dump的原因很多,這裡根據以往的經驗總結一下:

1 記憶體訪問越界

  a) 由於使用錯誤的下標,導致陣列訪問越界

  b) 搜尋字串時,依靠字串結束符來判斷字串是否結束,但是字串沒有正常的使用結束符

  c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字串操作函式,將目標字串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函式防止讀寫越界。

 

2 多執行緒程式使用了執行緒不安全的函式。

應該使用下面這些可重入的函式,尤其注意紅色標示出來的函式,它們很容易被用錯:

asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c) getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c) readdir_r(3c) getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c) getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)

 

3 多執行緒讀寫的資料未加鎖保護。

對於會被多個執行緒同時訪問的全域性資料,應該注意加鎖保護,否則很容易造成core dump

 

4 非法指標

  a) 使用空指標

  b) 隨意使用指標轉換。一個指向一段記憶體的指標,除非確定這段記憶體原先就分配為某種結構或型別,或者這種結構或型別的陣列,否則不要將它轉換為這種結構或型別的指標,而應該將這段記憶體拷貝到一個這種結構或型別中,再訪問這個結構或型別。這是因為如果這段記憶體的開始地址不是按照這種結構或型別對齊的,那麼訪問它時就很容易因為bus error而core dump.

 

5 堆疊溢位

不要使用大的區域性變數(因為區域性變數都分配在棧上),這樣容易造成堆疊溢位,破壞系統的棧和堆結構,導致出現莫名其妙的錯誤。

轉自:https://blog.csdn.net/melong100/article/details/6433047

https://blog.csdn.net/bzhxuexi/article/details/17840941