[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。
对于环形链表,我们最好在创建的同时就对其初始化,避免遗漏或者中间处理异常跳出,导致链表未初始化,在遍历的时候产生异常。

发布了27 篇原创文章 · 获赞 2 · 访问量 4605

猜你喜欢

转载自blog.csdn.net/xqjcool/article/details/104713521