天天看點

[crash分析][arm]應用程式Segmentation fault

定制業務程式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。

對于環形連結清單,我們最好在建立的同時就對其初始化,避免遺漏或者中間處理異常跳出,導緻連結清單未初始化,在周遊的時候産生異常。

繼續閱讀