您的位置:首页 > 理论基础 > 数据结构算法

《coredump问题原理探究》Linux x86版5.4节C风格数据结构内存布局之数组coredump例子

2013-03-21 23:30 579 查看
试定位一个coredump的例子来验证一下。

堆栈:

(gdb) bt
#0 0x43756109 in __memset_sse2 () from /lib/libc.so.6
#1 0x08048643 in main ()

汇编:

(gdb) frame 1
#1  0x08048643 in main ()
(gdb) disassemble
Dump of assembler code for function main:
0x080485c0 <+0>:     push   %ebp
0x080485c1 <+1>:     mov    %esp,%ebp
0x080485c3 <+3>:     and    $0xfffffff0,%esp
0x080485c6 <+6>:     sub    $0x30,%esp
0x080485c9 <+9>:     movl   $0x0,0x18(%esp)
0x080485d1 <+17>:    movl   $0x0,0x1c(%esp)
0x080485d9 <+25>:    movl   $0x0,0x20(%esp)
0x080485e1 <+33>:    movl   $0x0,0x24(%esp)
0x080485e9 <+41>:    movl   $0x0,0x2c(%esp)
0x080485f1 <+49>:    jmp    0x804860e <main+78>
0x080485f3 <+51>:    movl   $0x20,(%esp)
0x080485fa <+58>:    call   0x8048490 <_Znaj@plt>
0x080485ff <+63>:    mov    %eax,%edx
0x08048601 <+65>:    mov    0x2c(%esp),%eax
0x08048605 <+69>:    mov    %edx,0x18(%esp,%eax,4)
0x08048609 <+73>:    addl   $0x2,0x2c(%esp)
0x0804860e <+78>:    cmpl   $0x3,0x2c(%esp)
0x08048613 <+83>:    setle  %al
0x08048616 <+86>:    test   %al,%al
0x08048618 <+88>:    jne    0x80485f3 <main+51>
0x0804861a <+90>:    movb   $0x0,0x2b(%esp)
0x0804861f <+95>:    jmp    0x8048648 <main+136>
0x08048621 <+97>:    movsbl 0x2b(%esp),%edx
0x08048626 <+102>:   movsbl 0x2b(%esp),%eax
0x0804862b <+107>:   mov    0x18(%esp,%eax,4),%eax
0x0804862f <+111>:   movl   $0x20,0x8(%esp)
0x08048637 <+119>:   mov    %edx,0x4(%esp)
0x0804863b <+123>:   mov    %eax,(%esp)
0x0804863e <+126>:   call   0x8048470 <memset@plt>

=> 0x08048643 <+131>:   addb   $0x1,0x2b(%esp)

0x08048648 <+136>:   cmpb   $0x3,0x2b(%esp)
0x0804864d <+141>:   setle  %al
0x08048650 <+144>:   test   %al,%al
0x08048652 <+146>:   jne    0x8048621 <main+97>
0x08048654 <+148>:   mov    $0x0,%eax
0x08048659 <+153>:   jmp    0x8048663 <main+163>
0x0804865b <+155>:   mov    %eax,(%esp)
0x0804865e <+158>:   call   0x80484b0 <_Unwind_Resume@plt>
0x08048663 <+163>:   leave
0x08048664 <+164>:   ret
End of assembler dump.

由于coredump是在这一条指令下出错:

0x08048643 <+131>:   addb   $0x1,0x2b(%esp)

由memset的原型:

void *memset(void *s, int c, size_t n);

可知,会出现问题,要么,是第一个参数s非法,要么是n超出s的范围。

先看一下s是哪个,由

0x08048626 <+102>:   movsbl 0x2b(%esp),%eax
0x0804862b <+107>:   mov    0x18(%esp,%eax,4),%eax



0x0804863b <+123>:   mov    %eax,(%esp)

可知,

s的值存放在esp+0x18+eax*4。而eax的值是由esp+0x2b得来的。

由movsbl可知,esp+0x2b存放着一个char型,所以,

(gdb) x /c $esp+0x2b
0xbf88c15b:     1 '\001'

  由

0x08048621 <+97>:    movsbl 0x2b(%esp),%edx
0x08048626 <+102>:   movsbl 0x2b(%esp),%eax
0x0804862b <+107>:   mov    0x18(%esp,%eax,4),%eax
0x0804862f <+111>:   movl   $0x20,0x8(%esp)
0x08048637 <+119>:   mov    %edx,0x4(%esp)
0x0804863b <+123>:   mov    %eax,(%esp)
0x0804863e <+126>:   call   0x8048470 <memset@plt>

=> 0x08048643 <+131>:   addb   $0x1,0x2b(%esp)

0x08048648 <+136>:   cmpb   $0x3,0x2b(%esp)
0x0804864d <+141>:   setle  %al
0x08048650 <+144>:   test   %al,%al
0x08048652 <+146>:   jne    0x8048621 <main+97>

这个循环可知,esp+0x2b存放着索引值,也就是说,在崩溃的时候,它正指向数组第二个元素。而数组的基地址是esp+0x18。而且由于

0x0804862b <+107>:   mov    0x18(%esp,%eax,4),%eax

可知,它的步长是4,那么,这个数组的元素类型有可能是int,long(32-bit),指针(32-bit)。其中上面没有浮点操作的指令,所以,float可以排除。

由于,这个数组的元素是用于memset的第一个参数,所以,它应该是指针类型,且是在32-bit机器上。

看一下这个数组的第二个元素的值:

(gdb) x /wx $esp+0x18+4
0xbf88c14c:     0x00000000

也就是说,第二个元素为空指针,所以才会在memset里coredump。

看一下这个coredump的源代码:

#include <stdlib.h>
#include <string.h>
int main()
{
int* ptrArray[4] = { NULL, };

for ( int i = 0; i < 4; i += 2 )
{
ptrArray[i] = new int[8];
}

for ( char c = 0; c < 4; c++ )
{
memset( ptrArray[c], c, 8*sizeof(int) );
}

return 0;
}

就可以知道ptrArray[1]由于第一个循环,确实没有分配到内存,仍然为空。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐