前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《coredump问题原理探究》Linux x86版5.4节C风格数据结构内存布局之数组coredump例子

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

作者头像
血狼debugeeker
发布2018-09-20 14:38:44
9600
发布2018-09-20 14:38:44
举报
文章被收录于专栏:debugeeker的专栏debugeeker的专栏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344510

试定位一个coredump的例子来验证一下。

堆栈:

代码语言:javascript
复制
(gdb) bt
#0  0x43756109 in __memset_sse2 () from /lib/libc.so.6
#1  0x08048643 in main ()

汇编:

代码语言:javascript
复制
(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是在这一条指令下出错:

代码语言:javascript
复制
0x08048643 <+131>:   addb   $0x1,0x2b(%esp)

由memset的原型:

代码语言:javascript
复制
       void *memset(void *s, int c, size_t n);

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

先看一下s是哪个,由

代码语言:javascript
复制
   0x08048626 <+102>:   movsbl 0x2b(%esp),%eax
   0x0804862b <+107>:   mov    0x18(%esp,%eax,4),%eax

代码语言:javascript
复制
   0x0804863b <+123>:   mov    %eax,(%esp)

可知,

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

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

代码语言:javascript
复制
(gdb) x /c $esp+0x2b
0xbf88c15b:     1 '\001'

  由

代码语言:javascript
复制
   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。而且由于

代码语言:javascript
复制
   0x0804862b <+107>:   mov    0x18(%esp,%eax,4),%eax

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

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

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

代码语言:javascript
复制
(gdb) x /wx $esp+0x18+4
0xbf88c14c:     0x00000000

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

看一下这个coredump的源代码:

代码语言:javascript
复制
  #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;
  }

就可以知道ptrArray1由于第一个循环,确实没有分配到内存,仍然为空。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013年03月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档