Debug一个Segmentation fault的问题

先看下面的一个程序:

 cat test21.c 
void main(void)
{
	int *pointer;
	int i;
	pointer = malloc(sizeof(int));
	for(i = 0; 1; i++)
	{
		pointer[i] = i;
		printf("pointer[%d] = %d\n", i, pointer[i]);
	}
}

执行时,最终会crash掉:

pointer[33786] = 33786
pointer[33787] = 33787
pointer[33788] = 33788
pointer[33789] = 33789
Segmentation fault (core dumped)

我们的任务是分析 产生 Segfault的原因

先用gdb调入可执行程序,设置好断点:

$ gdb -q
(gdb) file test21
Reading symbols from /home/charles/test21...done.
(gdb) break 8
Breakpoint 1 at 0x8048435: file test21.c, line 8.
(gdb) condition  1 i == 33790
(gdb) info breakpoints 
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048435 in main at test21.c:8
	stop only if i == 33790
然后,运行 run命令:

pointer[33788] = 33788
pointer[33789] = 33789

Breakpoint 1, main () at test21.c:8
8			pointer[i] = i;
然后,运行 next:

(gdb) next

Program received signal SIGSEGV, Segmentation fault.
0x08048444 in main () at test21.c:8
8			pointer[i] = i;
(gdb) 
反汇编:

(gdb) disassemble 
Dump of assembler code for function main:
   0x08048414 <+0>:	push   %ebp
   0x08048415 <+1>:	mov    %esp,%ebp
   0x08048417 <+3>:	and    $0xfffffff0,%esp
   0x0804841a <+6>:	sub    $0x20,%esp
   0x0804841d <+9>:	movl   $0x4,(%esp)
   0x08048424 <+16>:	call   0x8048330 <malloc@plt>
   0x08048429 <+21>:	mov    %eax,0x1c(%esp)
   0x0804842d <+25>:	movl   $0x0,0x18(%esp)
   0x08048435 <+33>:	mov    0x18(%esp),%eax
   0x08048439 <+37>:	shl    $0x2,%eax
   0x0804843c <+40>:	add    0x1c(%esp),%eax
   0x08048440 <+44>:	mov    0x18(%esp),%edx
=> 0x08048444 <+48>:	mov    %edx,(%eax)
   0x08048446 <+50>:	mov    0x18(%esp),%eax
   0x0804844a <+54>:	shl    $0x2,%eax
   0x0804844d <+57>:	add    0x1c(%esp),%eax
   0x08048451 <+61>:	mov    (%eax),%eax
   0x08048453 <+63>:	mov    %eax,0x8(%esp)
   0x08048457 <+67>:	mov    0x18(%esp),%eax
   0x0804845b <+71>:	mov    %eax,0x4(%esp)
   0x0804845f <+75>:	movl   $0x8048550,(%esp)
   0x08048466 <+82>:	call   0x8048320 <printf@plt>
   0x0804846b <+87>:	addl   $0x1,0x18(%esp)
   0x08048470 <+92>:	jmp    0x8048435 <main+33>
End of assembler dump.
检查下 eax寄存器:

(gdb) print /x $eax
$2 = 0x806c000
(gdb) x $eax
0x806c000:	Cannot access memory at address 0x806c000
(gdb) 
EAX指向的地址不允许访问

看一下此时虚拟内存的布局:

(gdb) info proc mappings 
process 7323
Mapped address spaces:

	Start Addr   End Addr       Size     Offset objfile
	 0x8048000  0x8049000     0x1000        0x0 /home/charles/test21
	 0x8049000  0x804a000     0x1000        0x0 /home/charles/test21
	 0x804a000  0x804b000     0x1000     0x1000 /home/charles/test21
	 0x804b000  0x806c000    0x21000        0x0 [heap]
	0xb7e1a000 0xb7e1b000     0x1000        0x0 
	0xb7e1b000 0xb7fbf000   0x1a4000        0x0 /lib/i386-linux-gnu/libc-2.15.so
	0xb7fbf000 0xb7fc1000     0x2000   0x1a4000 /lib/i386-linux-gnu/libc-2.15.so
	0xb7fc1000 0xb7fc2000     0x1000   0x1a6000 /lib/i386-linux-gnu/libc-2.15.so
	0xb7fc2000 0xb7fc5000     0x3000        0x0 
	0xb7fda000 0xb7fdd000     0x3000        0x0 
	0xb7fdd000 0xb7fde000     0x1000        0x0 [vdso]
	0xb7fde000 0xb7ffe000    0x20000        0x0 /lib/i386-linux-gnu/ld-2.15.so
	0xb7ffe000 0xb7fff000     0x1000    0x1f000 /lib/i386-linux-gnu/ld-2.15.so
	0xb7fff000 0xb8000000     0x1000    0x20000 /lib/i386-linux-gnu/ld-2.15.so
	0xbffdf000 0xc0000000    0x21000        0x0 [stack]

可以看到,此时 EAX指向的地址是heap区的结束地址,这个虚拟地址是没有被映射到地址空间的,所以访问会出错。

再看一下  pointer的地址:

(gdb) print /x pointer
$3 = 0x804b008
(gdb) print pointer + i
$4 = (int *) 0x806c000
可见, 分给程序用的heap区域比总的少了8个字节。

可以看一下这个起始的8个字节的内容:

(gdb) x /8xw 0x804b000
0x804b000:	0x00000000	0x00000011	0x00000000	0x00000001
0x804b010:	0x00000002	0x00000003	0x00000004	0x00000005

前8个字节保存的是 heap header的信息。


参考:

 1. http://www.dedoimedo.com/computers/gdb.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值