2013-07-05 35 views
-1

我用gcc編譯我的程序,然後在a.out文件上運行gcc。 當我運行GDB內部PROGRAMM然後,我收到此錯誤:gdb with stange error:??。這是什麼意思?

Program received signal SIGSEGV, Segmentation fault. 
0xbffff118 in ??() 
(gdb) backtrace 
#0 0xbffff118 in ??() 
#1 0x00000000 in ??() 

這是什麼意思? 而且之前我,當試圖正常運行的程序,我得到這個錯誤:

*** stack smashing detected ***: ./benchmark terminated 
Aborted (core dumped) 

所以我看,這是對緩衝區溢出保護,我雙重檢查一切的應該是樣樣精,所以我禁用此使用標誌:

-fno-stack-protector 

編輯:我不張貼代碼,因爲我想弄清楚如何使用gdb的,而不是隻讓我的代碼工作。所以我是gdb的新手,但我現在成功地使用了它幾次。我仍然無法弄清楚什麼?意味着,在什麼情況下,gdb可能不會指向我的代碼中的相應調用,導致錯誤,爲什麼是第1幀0x0的地址?

+1

這意味着應用程序被隔離。通過您的評論來判斷,您可能會覆蓋堆棧或在其後面寫作。如果你使用警告('-Wall -Wextra')和調試符號('-g')編譯你的應用程序,它也會有幫助。另外你爲什麼要禁用堆棧保護機制?它確保您的程序安全。 – Nobilis

+0

我開始使用-g標誌,我現在使用了-Wall和-Wextra,並消除了所有的警告,但仍然是一樣的...... – zabeltech

+0

如果使用'-g',GDB應該能夠給你名稱和行失敗的功能。 – Nobilis

回答

0

一旦堆棧出現亂碼,無法告訴發生了什麼... 純c通常很難粉碎堆棧,您是在做任何程序集還是使用gotos/labels?那些是我見過的典型路線...

基本上會發生什麼是返回地址被覆蓋,並且當您嘗試返回到該垃圾地址堆棧沒有意義。

+0

我既不做assyembly也沒有任何gotos,我與printf一起出品的是,這個概率是在一個for循環,但並不總是在同一點 – zabeltech

+0

噢是的,printf可以做到這一點,如果你使用任何可變參數函數,你可能會得到不匹配的棧推/結束符......但編譯器通常會讀取它並給你一個警告。 –

+0

如何檢查本地數組的出界訪問?... – TheCodeArtist

4

當你像這樣得到一個垃圾回溯時,它幾乎肯定意味着你的堆棧被搗毀,並且實際的返回地址和堆棧幀指針已被覆蓋。

0xbffff118幾乎肯定是您的堆棧中的地址。我相信,在許多x86 Linux編譯器上,編譯器在虛擬地址0xc0000000處啓動堆棧,並且從那裏向下增長,因此以0xbfff開頭的任何地址都可能是堆棧地址。

通常,指令指針不應該在堆棧中。通常發生的方式是指向堆棧的值覆蓋存儲在堆棧中的返回地址,然後在當前函數返回時返回到被覆蓋的值。如果堆棧不可執行,就像它應該那樣,這會立即產生一個信號;如果堆棧是可執行的,那麼它可能不會崩潰,除非您被惡意利用,在這種情況下,您將會遇到不好的時間。

一旦你的堆棧被砸,backtrace命令不會有用,因爲你發現了。找出發生什麼事的最好方法是手動檢查堆棧並搜索可能的返回地址和幀指針。您可以使用x命令轉儲內存區域(有關詳細信息,請運行help x)。我喜歡使用x/<NUMBER>wx轉儲爲4字節的十六進制值。所以,這裏是如何轉儲一組數據開始堆棧指針$esp

(gdb) x/64wx $esp 
0xbffff7c0: 0x00000073 0xbffff9e9 0x0000000b 0x00000012 
0xbffff7d0: 0xbffff9e8 0x0be04aa0 0xbffff7f8 0x000018aa 
0xbffff7e0: 0x0be04aa0 0xbffff9e8 0x00000000 0x00000002 
0xbffff7f0: 0xbffff9e7 0x09a0bb10 0xbffff818 0x000018aa 
0xbffff800: 0x09a0bb10 0xbffff9e7 0x00000002 0x0000000e 
0xbffff810: 0xbffff9e6 0x015377f0 0xbffff838 0x000018aa 
0xbffff820: 0x015377f0 0xbffff9e6 0x00000008 0x00000011 
0xbffff830: 0xbffff9e5 0x01537860 0xbffff858 0x000018aa 
0xbffff840: 0x01537860 0xbffff9e5 0x00000003 0x0000000f 
0xbffff850: 0xbffff9e4 0x001ddbc0 0xbffff878 0x000018aa 
0xbffff860: 0x001ddbc0 0xbffff9e4 0x00000018 0x00000017 
0xbffff870: 0xbffff9e3 0x00177c50 0xbffff898 0x000018aa 
0xbffff880: 0x00177c50 0xbffff9e3 0xbffff8b8 0x00000000 
0xbffff890: 0xbffff9e2 0x00176050 0xbffff8b8 0x000018aa 
0xbffff8a0: 0x00176050 0xbffff9e2 0xbffff9e1 0x0000000c 
0xbffff8b0: 0xbffff9e1 0x00174920 0xbffffb08 0x00001b8a 

這裏,$esp0xbffff7c0,並$eip0x00001870(我得到了使用p/x $eip命令,但它也可以看到info regs得到所有的寄存器)。因此,每個堆棧幀都將成爲堆棧中較高的指針(0xbfff....),後跟一個類似於0x00001870的地址。尋找這些內存轉儲,我們可以相當肯定,這些都是棧幀:

0xbffff7f8 0x000018aa 
0xbffff818 0x000018aa 
0xbffff838 0x000018aa 
(etc.) 

這是我從一個高度遞歸程序中,我已經躺在身邊抓起一個例子,所以這就是爲什麼返回地址都一樣。一旦你發現沒有被砸壞了幾個不錯的堆棧幀,你可以按照幀指針自己:

(gdb) x/2wx 0xbffff7f8 
0xbffff7f8: 0xbffff818 0x000018aa 
(gdb) x/2wx 0xbffff818 
0xbffff818: 0xbffff838 0x000018aa 
(gdb) x/2wx 0xbffff838 
0xbffff838: 0xbffff858 0x000018aa 
(gdb) x/2wx 0xbffff858 
0xbffff858: 0xbffff878 0x000018aa 
... 

,然後如果你想指令地址轉換爲符號名稱,你可以再次使用x命令,如果您有調試符號,GDB會很樂意打印符號名稱:

(gdb) x 0x000018aa 
0x18aa <add_word+154>: 0x5d18c483 

這是在當你的堆棧已經被砸如何獲得一個實際有用的堆棧跟蹤快速入門。當然,最好避免這一點。我強烈建議你用-Wall -Wextra -Werror(也可以-pedantic,如果可以的話)編譯你的代碼,當然也不要用-fno-stack-protector,除非你真的有這樣做的充分理由。

+0

偉大的回答與此我將有一些東西來試用和學習! – zabeltech