




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、簡(jiǎn)介調(diào)試程序有很多方法,例如向屏幕上打印消息,使用調(diào)試器,或者只需仔細(xì)考慮程序如何運(yùn)行,并對(duì)問題進(jìn)行有根有據(jù)的猜測(cè)。在修復(fù) bug 之前,首先要確定在源程序中的位置。例如,當(dāng)一個(gè)程序產(chǎn)生崩潰或生成核心轉(zhuǎn)儲(chǔ)(core dump)時(shí),您就需要了解是哪行代碼發(fā)生了崩潰。在找到有問題的代碼行之后,就可以確定這個(gè)函數(shù)中變量的值,函數(shù)是如何調(diào)用的,更具體點(diǎn)說,為什么會(huì)發(fā)生這種錯(cuò)誤。使用調(diào)試器查找這些信息非常簡(jiǎn)單。本文將簡(jiǎn)要介紹幾種用于修復(fù)一些很難通過可視化地檢查代碼而發(fā)現(xiàn)的 bug 的技術(shù),并闡述了如何使用在 Linux on Power 架構(gòu)上可用的工具?;仨?yè)首調(diào)試內(nèi)存問題的工具和技術(shù)動(dòng)態(tài)內(nèi)存分配看起來
2、似乎非常簡(jiǎn)單:您可以根據(jù)需要分配內(nèi)存 使用 malloc() 或其變種 并在不需要時(shí)釋放這些內(nèi)存。實(shí)際上,內(nèi)存管理的問題是軟件中最為常見的 bug,因?yàn)橥ǔT诔绦騿?dòng)時(shí)這些問題并不明顯。例如,程序中的內(nèi)存泄漏可能開始并不為人注意,直到經(jīng)過多天甚至幾個(gè)月的運(yùn)行才會(huì)被發(fā)現(xiàn)。接下來的幾節(jié)將簡(jiǎn)要介紹如何使用流行的調(diào)試器 Valgrind 來發(fā)現(xiàn)并調(diào)試這些最常見的內(nèi)存 bug。在開始使用任何調(diào)試工具之前,請(qǐng)考慮這個(gè)工具是否對(duì)重新編譯應(yīng)用程序有益,是否可以支持具有調(diào)試信息的庫(kù)(-g 選項(xiàng))。如果沒有啟用調(diào)試信息,調(diào)試工具可以做的最好的事情也不過是猜測(cè)一段特定的代碼是屬于哪個(gè)函數(shù)的。這使得錯(cuò)誤消息和概要分析
3、輸出幾乎沒有什么用處。使用 -g 選項(xiàng),您就有可能獲得一些信息來直接指出相關(guān)的代碼行。ValgrindValgrind 已經(jīng)在 Linux 應(yīng)用程序開發(fā)社區(qū)中廣泛用來調(diào)試應(yīng)用程序。它尤其擅長(zhǎng)發(fā)現(xiàn)內(nèi)存管理的問題。它可以檢查程序運(yùn)行時(shí)的內(nèi)存泄漏問題。這個(gè)工具目前正由 Julian Seward 進(jìn)行開發(fā),并由 Paul Mackerras 移植到了 Power 架構(gòu)上。要安裝 Valgrind,請(qǐng)從 Valgrind 的 Web 站點(diǎn)上下載源代碼(參閱 參考資料)。切換到 Valgrind 目錄,并執(zhí)行下面的命令:# make# make check# make installValgrind 的
4、錯(cuò)誤報(bào)告Valgrind 的輸出格式如下:清單 1. Valgrind 的輸出消息 # valgrind du x s.=29404= Address 0x1189AD84 is 0 bytes after a block of size 12 alloc'd=29404= at 0xFFB9964: malloc (vg_replace_malloc.c:130)=29404= by 0xFEE1AD0: strdup (in /lib/tls/libc.so.6)=29404= by 0xFE94D30: setlocale (in /lib/tls/libc.so.6)=2940
5、4= by 0x10001414: main (in /usr/bin/du)=29404= 是進(jìn)程的 ID。消息 Address 0x1189AD84 is 0 bytes after a block of size 12 alloc'd 說明在這個(gè) 12 字節(jié)的數(shù)組后面沒有存儲(chǔ)空間了。第二行以及后續(xù)幾行說明內(nèi)存是在 130 行(vg_replace_malloc.c)的 strdup() 程序中進(jìn)行分配的。strdup() 是在 libc.so.6 庫(kù)的 setlocale() 中調(diào)用的;main() 調(diào)用了 setlocale()。未初始化的內(nèi)存最為常見的一個(gè) bug 是程序使用
6、了未初始化的內(nèi)存。未初始化的數(shù)據(jù)可能來源于: · 未經(jīng)初始化的變量· malloc 函數(shù)所分配的數(shù)據(jù),在寫入值之前使用了下面這個(gè)例子使用了一個(gè)未初始化的數(shù)組:清單 2. 使用未初始化的內(nèi)存 2 3 int i5; 4 5 if (i0 = 0) 6 i1=1; 7 return 0; 8 在這個(gè)例子中,整數(shù)數(shù)組 i5 沒有進(jìn)行初始化;因此,i0 包含的是一個(gè)隨機(jī)數(shù)。因此使用 i0 的值來判斷一個(gè)條件分支就會(huì)導(dǎo)致不可預(yù)期的問題。Valgrind 可以很容易捕獲這種錯(cuò)誤條件。當(dāng)您使用 Valgrind 運(yùn)行這個(gè)程序時(shí),就會(huì)接收到下面的消息:清單 3. Valgrind 的輸出消
7、息 # gcc g o test1 test1.c# valgrind ./test1.=31363= =31363= Conditional jump or move depends on uninitialised value(s)=31363= at 0x1000041C: main (test1.c:5)=31363= =31363= ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 1)=31363= malloc/free: in use at exit: 0 bytes in 0 blocks.=31363=
8、malloc/free: 0 allocs, 0 frees, 0 bytes allocated.=31363= For counts of detected errors, rerun with: -v=31363= No malloc'd blocks - no leaks are possible.Valgrind 的輸出說明,有一個(gè)條件分支依賴于文件 test1.c 中第 5 行中的一個(gè)未初始化的變量。內(nèi)存泄漏內(nèi)存泄漏是另外一個(gè)常見的問題,也是很多程序中最難判斷的問題。內(nèi)存泄漏的主要表現(xiàn)為:當(dāng)程序連續(xù)運(yùn)行時(shí),與程序相關(guān)的內(nèi)存(或堆)變得越來越大。結(jié)果是,當(dāng)這個(gè)程序所消耗的內(nèi)存
9、達(dá)到系統(tǒng)的上限時(shí),就會(huì)自己崩潰;或者會(huì)出現(xiàn)更嚴(yán)重的情況:掛起或?qū)е孪到y(tǒng)崩潰。下面是一個(gè)有內(nèi)存泄漏 bug 的示例程序:清單 4. 內(nèi)存泄漏示例 1 int main(void) 2 3 char *p1; 4 char *p2; 5 6 p1 = (char *) malloc(512); 7 p2 = (char *) malloc(512); 8 9 p1=p2; 10 11 free(p1); 12 free(p2); 13 上面的代碼分別給字符指針 p1 和 p2 分配了兩個(gè) 512 字節(jié)的內(nèi)存塊,然后將指向第一個(gè)內(nèi)存塊的指針設(shè)置為指向第二個(gè)內(nèi)存塊。結(jié)果是,第二個(gè)內(nèi)存塊的地址丟失了,并
10、導(dǎo)致內(nèi)存泄漏。在使用 Valgrind 運(yùn)行這個(gè)程序時(shí),會(huì)返回如下的消息:清單 5. Valgrind 的輸出消息 # gcc g o test2 test2.c# valgrind ./test2.=31468= Invalid free() / delete / delete=31468= at 0xFFB9FF0: free (vg_replace_malloc.c:152)=31468= by 0x100004B0: main (test2.c:12)=31468= Address 0x11899258 is 0 bytes inside a block of size 512 fre
11、e'd=31468= at 0xFFB9FF0: free (vg_replace_malloc.c:152)=31468= by 0x100004A4: main (test2.c:11)=31468= =31468= ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 1)=31468= malloc/free: in use at exit: 512 bytes in 1 blocks.=31468= malloc/free: 2 allocs, 2 frees, 1024 bytes allocated.=31
12、468= For counts of detected errors, rerun with: -v=31468= searching for pointers to 1 not-freed blocks.=31468= checked 167936 bytes.=31468= =31468= LEAK SUMMARY:=31468= definitely lost: 512 bytes in 1 blocks.=31468= possibly lost: 0 bytes in 0 blocks.=31468= still reachable: 0 bytes in 0 blocks.=314
13、68= suppressed: 0 bytes in 0 blocks.=31468= Use -leak-check=full to see details of leaked memory.正如您可以看到的一樣,Valgrind 報(bào)告說這個(gè)程序中有 512 字節(jié)的內(nèi)存丟失了。非法寫/讀這種情況發(fā)生在程序試圖對(duì)一個(gè)不屬于程序本身的內(nèi)存地址進(jìn)行讀寫時(shí)。在有些系統(tǒng)上,在發(fā)生這種錯(cuò)誤時(shí),程序會(huì)異常結(jié)束,并產(chǎn)生一個(gè)段錯(cuò)誤。下面這個(gè)例子就是一個(gè)常見的 bug,它試圖讀寫一個(gè)超出數(shù)組邊界的元素。清單 6. 非法讀寫 1 int main() 2 int i, *iw, *ir; 3 4 iw = (in
14、t *)malloc(10*sizeof(int); 5 ir = (int *)malloc(10*sizeof(int); 6 7 8 for (i=0; i<11; i+) 9 iwi = i; 10 11 for (i=0; i<11; i+) 12 iri = iwi; 13 14 free(iw); 15 free(ir); 16 從這個(gè)程序中我們可以看出,對(duì)于 iw10 和 ir10 的訪問都是非法的,因?yàn)?iw 和 ir 都只有 10 個(gè)元素,分別是從 0 到 9。請(qǐng)注意 int iw10 和 iw = (int *)malloc(10*sizeof(int) 是等
15、效的 它們都是用來給一個(gè)整數(shù)數(shù)組 iw 分配 10 個(gè)元素。當(dāng)您使用 Valgrind 運(yùn)行這個(gè)程序時(shí),會(huì)返回如下的消息:清單 7. Valgrind 的輸出消息 # gcc g o test3 test3.c# valgrind ./test3.=31522= Invalid write of size 4=31522= at 0x100004C0: main (test3.c:9)=31522= Address 0x11899050 is 0 bytes after a block of size 40 alloc'd=31522= at 0xFFB9964: malloc (vg
16、_replace_malloc.c:130)=31522= by 0x10000474: main (test10.c:4)=31522= =31522= Invalid read of size 4=31522= at 0x1000050C: main (test3.c:12)=31522= Address 0x11899050 is 0 bytes after a block of size 40 alloc'd=31522= at 0xFFB9964: malloc (vg_replace_malloc.c:130)=31522= by 0x10000474: main (tes
17、t10.c:4)=31522= =31522= ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 7 from 1)=31522= malloc/free: in use at exit: 0 bytes in 0 blocks.=31522= malloc/free: 2 allocs, 2 frees, 84 bytes allocated.=31522= For counts of detected errors, rerun with: -v=31522= No malloc'd blocks - no leaks are
18、 possible.在 test3.c 的第 9 行發(fā)現(xiàn)一個(gè)非法的 4 字節(jié)寫操作,在第 12 行發(fā)現(xiàn)一個(gè)非法的 4 字節(jié)讀操作。Valgrind 也可以幫助判斷內(nèi)存誤用的問題,例如: · 讀/寫已經(jīng)釋放的內(nèi)存· C+ 環(huán)境中錯(cuò)誤地使用 malloc/new 與 free/delete 的配對(duì)下面這個(gè)列表介紹了 POWER 架構(gòu)上 Valgrind 的狀態(tài): · memcheck 和 addrcheck 工具都可以很好地工作。然而,其他工具還沒有進(jìn)行大量的測(cè)試。另外,Helgrind (一個(gè)數(shù)據(jù)競(jìng)爭(zhēng)的檢測(cè)程序)在 POWER 上尚不能使用。· 所有的 3
19、2 位 PowerPC? 用戶模式的指令都可以支持,除了兩條非常少用的指令:lswx 和 stswx。具體來說,所有的浮點(diǎn)和 Altivec(VMX)指令都可以支持。· Valgrind 可以在 32 位或 64 位 PowerPC/Linux 內(nèi)核上工作,但是只能用于 32 位的可執(zhí)行程序。有關(guān) Valgrind 內(nèi)存調(diào)試的更多信息,請(qǐng)?jiān)L問 Valgrind HOW TO 站點(diǎn)。還可以參閱 Steve Best 的“Debugging Memory Problems”(Linux Magazine,2003 年 5 月)。參考資料 中有它們的鏈接除了 Valgrind 之外,還可以
20、使用其他幾個(gè)內(nèi)存調(diào)試工具;例如,Memwatch 和 Electric Fence。回頁(yè)首調(diào)試其他程序問題的工具和技術(shù)除了內(nèi)存 bug 之外,開發(fā)人員通常還會(huì)碰到程序雖然能夠成功編譯,但是在運(yùn)行時(shí)卻會(huì)產(chǎn)生內(nèi)核轉(zhuǎn)儲(chǔ)或段錯(cuò)誤的問題。有時(shí)在程序完成之后,程序的輸出可能與所期望或設(shè)計(jì)的不同。在這兩種情況中,可能代碼中存在您認(rèn)為正確而實(shí)際上錯(cuò)誤的情況。接下來的幾節(jié)中介紹的調(diào)試器將幫助您找到這些情況的原因。GNU 項(xiàng)目調(diào)試器GDB(GNU 項(xiàng)目調(diào)試器)可以讓您了解程序在執(zhí)行時(shí)“內(nèi)部” 究竟在干些什么,以及在程序發(fā)生崩潰的瞬間正在做什么。GDB 做以下 4 件主要的事情來幫助您捕獲程序中的 bug:
21、83; 在程序啟動(dòng)之前指定一些可以影響程序行為的變量或條件· 在某個(gè)指定的地方或條件下暫停程序· 在程序停止時(shí)檢查已經(jīng)發(fā)生了什么· 在程序執(zhí)行過程中修改程序中的變量或條件,這樣就可以體驗(yàn)修復(fù)一個(gè) bug 的成果,并繼續(xù)了解其他 bug要調(diào)試的程序可以是使用 C、C+、Pascal、Objective-C 以及其他很多語(yǔ)言編寫的。GDB 的二進(jìn)制文件名是 gdb。gdb 中有很多命令。使用 help 命令可以列出所有的命令,以及關(guān)于如何使用這些命令的介紹。下表給出了最常用的 GDB 命令。表 1. gdb 中最常用的命令命令說明例子help 顯示命令類別help -
22、 顯示命令類別help breakpoints - 顯示屬于 breakpoints 類別的命令help break - 顯示 break 命令的解釋run 啟動(dòng)所調(diào)試的程序? kill 終止正在調(diào)試的程序的執(zhí)行通常這會(huì)在要執(zhí)行的代碼行已經(jīng)超過了您想要調(diào)試的代碼時(shí)使用。執(zhí)行 kill 會(huì)重置斷點(diǎn),并從頭再次運(yùn)行這個(gè)程序cont 所調(diào)試的程序運(yùn)行到一個(gè)斷點(diǎn)、異常或單步之后,繼續(xù)執(zhí)行? info break 顯示當(dāng)前的斷點(diǎn)或觀察點(diǎn)? break 在指定的行或函數(shù)處設(shè)置斷點(diǎn)break 93 if i=8 - 當(dāng)變量 i 等于 8 時(shí),在第 93 行停止程序執(zhí)行Step 單步執(zhí)行程序,直到它到達(dá)一個(gè)不
23、同的源代碼行。您可以使用 s 來代表 step 命令? Next 與 step 命令類似,只是它不會(huì)“單步跟蹤到”子例程中? print 打印一個(gè)變量或表達(dá)式的值print pointer - 打印變量指針的內(nèi)容print *pointer - 打印指針?biāo)赶虻臄?shù)據(jù)結(jié)構(gòu)的內(nèi)容delete 刪除某些斷點(diǎn)或自動(dòng)顯示表達(dá)式delete 1 - 刪除斷點(diǎn) 1。斷點(diǎn)可以通過 info break 來顯示 watch 為一個(gè)表達(dá)式設(shè)置一個(gè)觀察點(diǎn)。當(dāng)表達(dá)式的值發(fā)生變化時(shí),這個(gè)觀察點(diǎn)就會(huì)暫停程序的執(zhí)行? where 打印所有堆棧幀的棧信息where - 不使用參數(shù),輸出當(dāng)前線程的堆棧信息where all -
24、 輸出當(dāng)前線程組中所有線程的堆棧信息where threadindex - 輸出指定線程的堆棧信息attach 開始查看一個(gè)已經(jīng)運(yùn)行的進(jìn)程attach <process_id> - 附加到進(jìn)程 process_id 上。process_id 可以使用 ps 命令找到info thread 顯示當(dāng)前正在運(yùn)行的線程? thread apply threadno command 對(duì)一個(gè)線程運(yùn)行 gdb 命令thread apply 3 where - 對(duì)線程 3 運(yùn)行 where 命令Thread threadno 選擇一個(gè)線程作為當(dāng)前線程? 如果一個(gè)程序崩潰了,并生成了一個(gè) core
25、文件,您可以查看 core 文件來判斷進(jìn)程結(jié)束時(shí)的狀態(tài)。使用下面的命令啟動(dòng) gdb:# gdb programname corefilename 要調(diào)試一個(gè) core 文件,您需要可執(zhí)行程序、源代碼文件以及 core 文件。要對(duì)一個(gè) core 文件啟動(dòng) gdb,請(qǐng)使用 -c 選項(xiàng):# gdb -c core programname gdb 會(huì)顯示是哪行代碼導(dǎo)致這個(gè)程序產(chǎn)生了核心轉(zhuǎn)儲(chǔ)。默認(rèn)情況下,核心轉(zhuǎn)儲(chǔ)在 Novell 的 SUSE LINUX Enterprise Server 9(SLES 9)和 Red Hat? Enterprise Linux Advanced Server(RHEL
26、 AS 4)上都是禁用的。要啟用核心轉(zhuǎn)儲(chǔ),請(qǐng)以 root 用戶的身份在命令行中執(zhí)行 ulimit c unlimited。清單 8 中的例子闡述了如何使用 gdb 來定位程序中的 bug。清單 8 是一段包含 bug 的 C+ 代碼。清單 8 中的 C+ 程序試圖構(gòu)建 10 個(gè)鏈接在一起的數(shù)字框(number box),例如:圖 1. 一個(gè)包含 10 個(gè)鏈接在一起的數(shù)字框的列表然后試圖從這個(gè)列表中逐個(gè)刪除數(shù)字框。編譯并運(yùn)行這個(gè)程序,如下所示:清單 9. 編譯并運(yùn)行這個(gè)程序 # g+ -g -o gdbtest1 gdbtest1.cpp# ./gdbtest1Number Box "
27、0" createdNumber Box "1" createdNumber Box "2" createdNumber Box "3" createdNumber Box "4" createdNumber Box "5" createdNumber Box "6" createdNumber Box "7" createdNumber Box "8" createdNumber Box "9" crea
28、tedlist createdNumber Box "9" deletedSegmentation fault正如您可以看到的一樣,這個(gè)程序會(huì)導(dǎo)致段錯(cuò)誤。調(diào)用 gdb 來看一下這個(gè)問題,如下所示:清單 10. 調(diào)用 gdb # gdb ./gdbtest1GNU gdb 6.2.1Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or
29、 distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "ppc-suse-linux".Using host libthread_db library "/lib/tls/libthread_db.
30、so.1".(gdb)您知道段錯(cuò)誤是在數(shù)字框 "9" 被刪除之后發(fā)生的。執(zhí)行 run 和 where 命令來精確定位段錯(cuò)誤發(fā)生在程序中的什么位置。清單 11. 執(zhí)行 run 和 where 命令 (gdb) runStarting program: /root/test/gdbtest1 Number Box "0" createdNumber Box "1" createdNumber Box "2" createdNumber Box "3" createdNumber Box &
31、quot;4" createdNumber Box "5" createdNumber Box "6" createdNumber Box "7" createdNumber Box "8" createdNumber Box "9" createdlist createdNumber Box "9" deletedProgram received signal SIGSEGV, Segmentation fault.0x10000f74 in NumBox<
32、int>:GetNext (this=0x0) at gdbtest1.cpp:1414 NumBox<T>*GetNext() const return Next; (gdb) where#0 0x10000f74 in NumBox<int>:GetNext (this=0x0) at gdbtest1.cpp:14#1 0x10000d10 in NumChain<int>:RemoveBox (this=0x10012008, item_to_remove=0xffffe200) at gdbtest1.cpp:63#2 0x10000978
33、in main (argc=1, argv=0xffffe554) at gdbtest1.cpp:94(gdb)跟蹤信息顯示這個(gè)程序在第 14 行 NumBox<int>:GetNext (this=0x0) 接收到一個(gè)段錯(cuò)誤。這個(gè)數(shù)字框上 Next 指針的地址是 0x0,這對(duì)于一個(gè)數(shù)字框來說是一個(gè)無效的地址。從上面的跟蹤信息可以看出,GetNext 函數(shù)是由 63 行調(diào)用的??匆幌略?gdbtest1.cpp 的 63 行附近發(fā)生了什么:清單 12. gdbtest1.cpp 54 else 55 temp->SetNext (current->GetNext();
34、 56 delete temp; 57 temp = 0; 58 return 0; 59 60 61 current = 0; 62 temp = current; 63 current = current->GetNext(); 64 65 66 return -1;第 61 行 current=0 將這個(gè)指針設(shè)置為一個(gè)無效的地址,這正是產(chǎn)生段錯(cuò)誤的根源。注釋掉第 61 行,將其保存為 gdbtest2.cpp,然后編譯并重新運(yùn)行。清單 13. 再次運(yùn)行程序(gdbtest2.cpp) # g+ -g -o gdbtest2 gdbtest2.cpp# ./gdbtest2Numbe
35、r Box "0" createdNumber Box "1" createdNumber Box "2" createdNumber Box "3" createdNumber Box "4" createdNumber Box "5" createdNumber Box "6" createdNumber Box "7" createdNumber Box "8" createdNumber Box "
36、9" createdlist createdNumber Box "9" deletedNumber Box "0" deleted這個(gè)程序現(xiàn)在可以成功完成而不會(huì)出現(xiàn)段錯(cuò)誤了。然而,結(jié)果并不像我們預(yù)期的一樣:程序在刪除 Number Box "9"之后刪除了 Number Box "0",而不像我們期望的一樣刪除 Number Box "8,"。使用 gdb 再次來看一下。清單 14. 再次使用 gdb 進(jìn)行查看 # gdb ./gdbtest2GNU gdb 6.2.1Copyrig
37、ht 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show
38、 warranty" for details.This GDB was configured as "ppc-suse-linux".Using host libthread_db library "/lib/tls/libthread_db.so.1".(gdb) break 94 if i=8Breakpoint 1 at 0x10000968: file gdbtest2.cpp, line 94.(gdb) runStarting program: /root/test/gdbtest2 Number Box "0"
39、 createdNumber Box "1" createdNumber Box "2" createdNumber Box "3" createdNumber Box "4" createdNumber Box "5" createdNumber Box "6" createdNumber Box "7" createdNumber Box "8" createdNumber Box "9" createdlist
40、 createdNumber Box "9" deletedBreakpoint 1, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:9494 list ->RemoveBox(i);您可能希望找出為什么這個(gè)程序刪除的是 Number Box 0,而不是 Number Box 8,因此需要在您認(rèn)為程序會(huì)刪除 Number Box 8 的地方停止程序。設(shè)置這個(gè)斷點(diǎn):break 94 if i=8,可以在 i 等于 8 時(shí)在第 94 行處停止程序。然后單步跟蹤到 RemoveBox() 函數(shù)中。 清單 15. 單步跟蹤到 R
41、emoveBox() 函數(shù)中 (gdb) s38 NumBox<T> *temp = 0; (gdb) s40 while (current != 0) (gdb) print pointer$1 = (NumBox<int> *) 0x100120a8 (gdb) print *pointer$2 = Num = 0, Next = 0x0(gdb)指針早已指向了 Number Box "0",因此這個(gè) bug 可能就存在于程序刪除 Number Box "9" 的地方。要在 gdb 中重新啟動(dòng)這個(gè)程序,請(qǐng)使用 kill 刪除原
42、來的斷點(diǎn),然后添加一個(gè) i 等于 9 時(shí)的新斷點(diǎn),然后再次運(yùn)行這個(gè)程序。清單 16. 在 gdb 中重新啟動(dòng)程序 (gdb) killKill the program being debugged? (y or n) y(gdb) info breakNum Type Disp Enb Address What1 breakpoint keep y 0x10000968 in main at gdbtest2.cpp:94 stop only if i = 8 breakpoint already hit 1 time(gdb) delete 1(gdb) break 94 if i=9Bre
43、akpoint 2 at 0x10000968: file gdbtest2.cpp, line 94.(gdb) runStarting program: /root/test/gdbtest2 Number Box "0" createdNumber Box "1" createdNumber Box "2" createdNumber Box "3" createdNumber Box "4" createdNumber Box "5" createdNumber Bo
44、x "6" createdNumber Box "7" createdNumber Box "8" createdNumber Box "9" createdlist createdBreakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:9494 list ->RemoveBox(i);(gdb)當(dāng)這一次單步跟蹤 RemoveBox() 函數(shù)時(shí),要特別注意 list->pointer 正在指向哪一個(gè)數(shù)字框,因?yàn)?bug 可能就在于 lis
45、t->pointer 開始指向 Number Box "0" 的地方。請(qǐng)使用 display *pointer 命令來查看,這會(huì)自動(dòng)顯示這個(gè)函數(shù)。清單 17. 使用 display *pointer 命令進(jìn)行監(jiān)視 Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:9494 list ->RemoveBox(i);(gdb) sNumChain<int>:RemoveBox (this=0x10012008, item_to_remove=0xffffe200) at gdbtes
46、t2.cpp:3737 NumBox<T> *current = pointer;(gdb) display *pointer1: *this->pointer = Num = 9, Next = 0x10012098(gdb) s38 NumBox<T> *temp = 0; 1: *this->pointer = Num = 9, Next = 0x10012098(gdb) s40 while (current != 0) 1: *this->pointer = Num = 9, Next = 0x10012098(gdb) s41 if (cu
47、rrent->GetValue() = item_to_remove) 1: *this->pointer = Num = 9, Next = 0x10012098(gdb) sNumBox<int>:GetValue (this=0x100120a8) at gdbtest2.cpp:1616 const T& GetValue () const return Num; (gdb) sNumChain<int>:RemoveBox (this=0x10012008, item_to_remove=0xffffe200) at gdbtest2.cp
48、p:4242 if (temp = 0) 1: *this->pointer = Num = 9, Next = 0x10012098(gdb) s44 if (current->GetNext() = 0) 1: *this->pointer = Num = 9, Next = 0x10012098(gdb) sNumBox<int>:GetNext (this=0x100120a8) at gdbtest2.cpp:1414 NumBox<T>*GetNext() const return Next; (gdb) sNumChain<int&
49、gt;:RemoveBox (this=0x10012008, item_to_remove=0xffffe200) at gdbtest2.cpp:5050 delete current;1: *this->pointer = Num = 9, Next = 0x10012098(gdb) sNumBox (this=0x100120a8) at gdbtest2.cpp:1010 std:cout << "Number Box " <<""" << GetValue() <<"
50、"" <<" deleted" << std:endl;(gdb) sNumBox<int>:GetValue (this=0x100120a8) at gdbtest2.cpp:1616 const T& GetValue () const return Num; (gdb) sNumber Box "9" deletedNumBox (this=0x100120a8) at gdbtest2.cpp:1111 Next = 0;(gdb) sNumChain<int>:Rem
51、oveBox (this=0x10012008, item_to_remove=0xffffe200) at gdbtest2.cpp:5151 current = 0;1: *this->pointer = Num = 0, Next = 0x0(gdb) s53 return 0;1: *this->pointer = Num = 0, Next = 0x0(gdb) s0x10000d1c 66 return -1;1: *this->pointer = Num = 0, Next = 0x0從上面的跟蹤過程中,您可以看到 list->pointer 在刪除 Nu
52、mber Box "9" 之后指向了 Number Box "0"。這個(gè)邏輯并不正確,因?yàn)樵趧h除 Number Box "9" 之后,list->pointer 應(yīng)該指向的是 Number Box "8"?,F(xiàn)在非常顯然我們應(yīng)該在第 50 行之前添加一條語(yǔ)句 pointer = pointer->GetNext();,如下所示:清單 18. 在第 50 行之前添加一條 pointer = pointer->GetNext(); 語(yǔ)句 49 else 50 pointer = pointer->
53、GetNext(); 51 delete current; 52 current = 0; 53 54 return 0;將新修改之后的程序保存為 gdbtest3.cpp,然后編譯并再次運(yùn)行。清單 19. 再次運(yùn)行程序(gdbtest3.cpp) # g+ -g -o gdbtest3 gdbtest3.cpp# ./gdbtest3Number Box "0" createdNumber Box "1" createdNumber Box "2" createdNumber Box "3" createdNum
54、ber Box "4" createdNumber Box "5" createdNumber Box "6" createdNumber Box "7" createdNumber Box "8" createdNumber Box "9" createdlist createdNumber Box "9" deletedNumber Box "8" deletedNumber Box "7" deletedNumber Box "6&
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030國(guó)內(nèi)口腔衛(wèi)生用品行業(yè)市場(chǎng)發(fā)展前景及競(jìng)爭(zhēng)策略與投資風(fēng)險(xiǎn)研究報(bào)告
- 2025-2030國(guó)內(nèi)中藥片劑行業(yè)市場(chǎng)發(fā)展分析及競(jìng)爭(zhēng)格局與投資機(jī)會(huì)研究報(bào)告
- 2025-2030商業(yè)捕魚行業(yè)市場(chǎng)現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評(píng)估規(guī)劃分析研究報(bào)告
- 2025-2030味精產(chǎn)業(yè)行業(yè)市場(chǎng)現(xiàn)狀供需分析及投資評(píng)估規(guī)劃分析研究報(bào)告
- 2025-2030可穿戴安全設(shè)備行業(yè)市場(chǎng)現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評(píng)估規(guī)劃分析研究報(bào)告
- 2025-2030卷紙箱行業(yè)風(fēng)險(xiǎn)投資發(fā)展分析及投資融資策略研究報(bào)告
- 2025-2030半甜白葡萄酒行業(yè)發(fā)展分析及發(fā)展趨勢(shì)預(yù)測(cè)與投資風(fēng)險(xiǎn)研究報(bào)告
- 2025-2030醫(yī)用丁基橡膠行業(yè)市場(chǎng)現(xiàn)狀供需分析及投資評(píng)估規(guī)劃分析研究報(bào)告
- 2025-2030化學(xué)藥品產(chǎn)業(yè)市場(chǎng)深度調(diào)研及發(fā)展趨勢(shì)與投資前景研究報(bào)告
- 2025-2030包裝紙產(chǎn)業(yè)行業(yè)市場(chǎng)現(xiàn)狀供需分析及投資評(píng)估規(guī)劃分析研究報(bào)告
- 人際交往與溝通課件第一章 人際交往與溝通概述
- 養(yǎng)老院安全知識(shí)培訓(xùn)
- 煤炭行業(yè)的信息化與智能化轉(zhuǎn)型
- 抗生素合理應(yīng)用課件
- 2024年廣西廣投資本管理有限公司招聘筆試參考題庫(kù)含答案解析
- 酒店露營(yíng)基地項(xiàng)目計(jì)劃書
- 小學(xué)趣味科學(xué) 3D打印技術(shù) 課件
- 輕量化目標(biāo)檢測(cè)模型的研究
- 醫(yī)療器械人因工程與可用性測(cè)試總結(jié)
- 管道中的流量與壓強(qiáng)的關(guān)系及特殊情況分析
- 完整版工資條模板
評(píng)論
0/150
提交評(píng)論