如果你覺得你已經理解了段錯誤的根源,也知道了如何防止段錯誤,那麼可以到此為止。否則,下面的內容或許對你有所啟發。
我們開始為指針所指向的地址分配內存:
vcc8c3Ryb25nPrbOtO3O8zwvc3Ryb25nPrXEx7DPpjo8L3A+DQo8cD48aW1nIGFsdD0="這裡寫圖片描述" src="http://www.bkjia.com/uploads/allimg/150504/045T33G3-1.png" title="\" />
上面的圖告訴我們一些信息:
紅線勾勒出的內容是:
從函數func1
的局部變量中取出指針dest(char ** 型)
指向的地址,正確的代碼中地址是0x7fffffffddc0
,而錯誤的代碼中地址則是0x0
.
下一步即將執行黃線勾勒出的內容
/*
注意這裡的rax在錯誤的代碼中為0x0
而rdx的值為malloc出的內存地址0x602010
*/
mov QWORD PTR [rax],rdx
那麼,當執行上面的代碼時,錯誤的代碼試圖將malloc分配出的在堆上的內存地址當作值放在指針dest
指向的地址中。
地址:0x0 值:0x602010
那麼就出現了上篇所說的,0x0
是不能被訪問的地址,也就不可能完成賦值操作。所以就會出現段錯誤:
對於很多人來講。上面的分析比第一篇要深入一些,也許看得到真相前的每一步才能讓人踏實。
現在,我們來看看什麼是段錯誤。
下圖是一個進程地址空間的描述,這是一個舊圖,網上到處都是,但可以用來理解VMA:
上面這幅圖會告訴我們什麼呢?
內核虛擬內存空間,你肯定訪問不了.
用戶棧,用戶進程啟動就會有這樣一個結構,你超過它的上界就到了內核虛擬內存空間,就會出現段錯誤.
內存映射mmp區域.
堆,malloc、calloc就在這裡找地址分配.(事實上不僅如此)
代碼、數據段 包括全局變量、靜態變量、代碼、數據等等.
如果你訪問了內核虛擬內存空間(就是比ebp大的空間,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
.
我想,對於這樣一個簡單的c程序,上面的信息足夠了.
也許後面還想看看mmap、mm的fault處理、頁異常處理還有signal的一些東西.
但本篇,就此結束.