本篇將繼續上1篇來討論段毛病(Segmentation fault)。
上1篇:
你的C/C++程序為何沒法運行?揭秘Segmentation fault(1)
如果你覺得你已理解了段毛病的本源,也知道了如何避免段毛病,那末可以到此為止。否則,下面的內容也許對你有所啟發。
我們開始為指針所指向的地址分配內存:
注意,(*dest) = (char*)malloc(sizeof(char)*n);
的右側已履行,但還沒有將分配出的地址賦給指針*dest
。
接下來,我們的主角段毛病的前夕:
上面的圖告知我們1些信息:
紅線勾畫出的內容是:
從函數func1
的局部變量中取出指針dest(char ** 型)
指向的地址,正確的代碼中地址是0x7fffffffddc0
,而毛病的代碼中地址則是0x0
.
下1步行將履行黃線勾畫出的內容
/*
注意這里的rax在毛病的代碼中為0x0
而rdx的值為malloc出的內存地址0x602010
*/
mov QWORD PTR [rax],rdx
那末,當履行上面的代碼時,毛病的代碼試圖將malloc分配出的在堆上的內存地址當作值放在指針dest
指向的地址中。
地址:0x0 值:0x602010
那末就出現了上篇所說的,0x0
是不能被訪問的地址,也就不可能完成賦值操作。所以就會出現段毛病:
對很多人來說。上面的分析比第1篇要深入1些,或許看得到真相前的每步才能讓人踏實。
現在,我們來看看甚么是段毛病。
下圖是1個進程地址空間的描寫,這是1個舊圖,網上到處都是,但可以用來理解VMA:
上面這幅圖會告知我們甚么呢?
內核虛擬內存空間,你肯定訪問不了.
用戶棧,用戶進程啟動就會有這樣1個結構,你超過它的上界就到了內核虛擬內存空間,就會出現段毛病.
內存映照mmp區域.
堆,malloc、calloc就在這里找地址分配.(事實上不但如此)
代碼、數據段 包括全局變量、靜態變量、代碼、數據等等.
如果你訪問了內核虛擬內存空間(就是比ebp大的空間,1都不行)、代碼段、數據段都會引發段毛病。
在上篇的例子中,是由于訪問了圖中紅色圈出的保存區域釀成的段毛病。
補充1下x86_64的VMA-layout:
。
方法有很多。我也只會1個,畢竟我不寫C/C++,更不是這方面的老手。
利用coredump+gdb來做。
獲得coredump的方法:
1.在shell中`ulimit -c unlimited`
2.運行你產生了段毛病的程序
有了coredump,就能夠拿gdb來掰掰了gdb xx xxcoredump
.
上圖有幾個信息:
1.signal 11,是甚么呢?
![]()
2.Segmentation fualt 段毛病
3.stack2.c
中的第8行出現毛病.
4.仔細視察還會看到函數func1
的參數dest=0x0
.
我想,對這樣1個簡單的c程序,上面的信息足夠了.
或許后面還想看看mmap、mm的fault處理、頁異常處理還有signal的1些東西.
但本篇,就此結束.