定制業務程式prog,在客戶裝置上運作後出現Segmentation fault。
為了定位問題,編譯了未strip的版本,并修改裝置core file size為unlimited。重新運作,産生了core_prog_25647。
使用toolchain gdb工具打開,開始調試。
...//省略無關
Program terminated with signal 11, Segmentation fault.
#0 0x0000bb88 in nfq_update ()
(gdb) bt
#0 0x0000bb88 in nfq_update ()
#1 0x0000c72c in nfq_create ()
#2 0x0000ade0 in main ()
從調用棧看是cransh在nfq_update函數中,我們反彙編nfq_update,找到出錯指令位置。
(gdb) disass
Dump of assembler code for function nfq_update:
0x0000bb44 <nfq_update+0>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x0000bb48 <nfq_update+4>: subs r4, r1, #0 ; 0x0
0x0000bb4c <nfq_update+8>: sub sp, sp, #28 ; 0x1c
0x0000bb50 <nfq_update+12>: str r0, [sp, #4] //5. [sp + 4] = r0, 第一個入參
0x0000bb54 <nfq_update+16>: beq 0xbb64 <nfq_update+32>
0x0000bb58 <nfq_update+20>: ldr r3, [r4]
0x0000bb5c <nfq_update+24>: cmp r3, #0 ; 0x0
0x0000bb60 <nfq_update+28>: bne 0xbf98 <nfq_update+1108>
0x0000bb64 <nfq_update+32>: mov r10, #0 ; 0x0
0x0000bb68 <nfq_update+36>: ldr r9, [sp, #4] //4. r9 = [sp + 4]
0x0000bb6c <nfq_update+40>: mov r11, #0 ; 0x0
0x0000bb70 <nfq_update+44>: ldr r1, [r9, #28]! //3. r1 = [r9 + 28],感歎号表示r9會更新為r9 + 28
0x0000bb74 <nfq_update+48>: str r1, [sp, #8]
0x0000bb78 <nfq_update+52>: mov r2, r1 //2. r2 = r1
0x0000bb7c <nfq_update+56>: cmp r9, r2
0x0000bb80 <nfq_update+60>: beq 0xbbf0 <nfq_update+172>
0x0000bb84 <nfq_update+64>: mov r8, r2
0x0000bb88 <nfq_update+68>: ldr r2, [r2] //1. 出錯指令
0x0000bb8c <nfq_update+72>: cmp r10, #0 ; 0x0
0x0000bb90 <nfq_update+76>: str r2, [sp, #8]
0x0000bb94 <nfq_update+80>: beq 0xbe10 <nfq_update+716>
...//省略無關
從反彙編看,出錯指令是加載記憶體位址為r2的資料,并存入r2中。(小tips:大多數情況下這種操作是連結清單的x = x->next操作)。檢視寄存器可以看到r2是0空位址,通路空位址導緻段錯誤發生。
我們一步一步反推。先是找到 r2是從r1得到。繼續分析可知r1是r9指向記憶體位址偏移28個位元組的資料。而r9是sp棧指針指向記憶體位址偏移4個位元組的資料。最終可知這個位置存放的是第一個入參nfq指針位址。
(gdb) info reg
r0 0x891d8 561624
r1 0x0 0
r2 0x0 0
r3 0x100004 1048580
r4 0x0 0
r5 0x891d8 561624
r6 0xbefffbcc 3204447180
r7 0x3e7 999
r8 0x0 0
r9 0x891f4 561652
r10 0x0 0
r11 0x0 0
r12 0x863c4 549828
sp 0xbefff830 0xbefff830
lr 0xc72c 50988
pc 0xbb88 0xbb88 <nfq_update+68>
fps 0x0 0
cpsr 0x20000010 536870928
至此脈絡基本清晰,順着推下來, nfq結構偏移 28個位元組指向的結構變量就是出錯的變量。對照代碼可知是
list_head List;因為在Create過程中異常進入clean up邏輯,nfq的List并未初始化,是以List的next和prev都是NULL。而在nfq_update中node = List->next, 然後在通路下一個節點時使用了node = node->next。産生了空指針引用,導緻程序crash。
對于環形連結清單,我們最好在建立的同時就對其初始化,避免遺漏或者中間處理異常跳出,導緻連結清單未初始化,在周遊的時候産生異常。