使用libumem定位memory leak和memory corruption(2)


 

 

今天来介绍libumem中使用的数据结构。上次讲到每个cache会管理一类对象,在这里是内存对象。每个cache维护着相同大小的N块buffer,每个buffer的结构如下:

 

 

每一块buffer由4部分组成,Metadata section有8个字节,User data section就是用户可以使用的内存区域,返回给用户的BUFADDR也就是指User Data Section的起始地址。Redzone是用来隔离User Data和Debug Meta Data的。Redzone也是8个字节,其中的第2个四字节编码了User data section中用户实际分配区域的大小。Debug Section也是8个字节,指明了该buffer的状态,是allocated还是freed。

 

 

下面我们来看User Data Section:

 

 

每一块buffer都是固定大小的,umem_alloc_112管理的内存都是112字节,umem_alloc_64管理的都是64字节。我的理解是umem_alloc_N,这里的N指的是 User Data Section + Redzone

再看上一次的程序:
int *p = (int*)malloc(50);      //p = 0x809cf88
p = (int*)malloc(100);          //p = 0x80a0f88
free(p);

可以看到malloc使用的是umem_alloc_64, 我们来看一看这个64字节是什么,p=(int*)malloc(50)得到p=0x809cf88 = 0x809cf80+8 –>注意:malloc返回的地址是buffer 起始地址+8字节,也就是说返回的是user data section的地址!

> 809cf80/20X    //20X表示以16进制方式打印20个4字节
0x809cf80:       3a              3a10bfc6         baddcafe       baddcafe        baddcafe
                  baddcafe        baddcafe        baddcafe       baddcafe        baddcafe
                  baddcafe        baddcafe        baddcafe       baddcafe        babb cafe
                  baddcafe        feedface         38df              809e080         a919286d

 

 

buffer有两种正确的状态:allocated或者freed。在分配状态时,libumem在user data中填充0xbaddcafe,在freed状态下,libumem在user data中填充0xdeadbeef。绿色部分8字节是meta section,蓝色部分是redzone,redzone在allocated状态下,第一个4字节填充0xfeedface,第二个4字节=(allocated bytes + 8)x251 +1。所以这里0x38df意味着:
> 38df=D    //把0x38df转化成10进制=14559
                14559    –>所以用户申请的内存大小= (14559-1)/251 – 8 = 50字节, 和malloc(50)吻合

 

 

注意我用红色自己标记的0xbb。在上面的memory dump中,共有14个baddcafe,也就是说user data section一共14×4=56字节。但是malloc只申请了50字节,libumem使用0xbb作为分隔。注意0xbabbcafe中0xba处于高字节,所以实际在内存中从低地址到高地址排列是 0xfe 0xca 0xbb 0xba 0xfe 0xca 0xdd 0xba 0xfeedface …确实在0xfeedface之前是6个字节。最后说明一下debug meta section。第一个4字节是指向umem_bufctl_audit数据结构的指针,第二个4字节是一个checksum。

Debug meta section中的两个4字节(BufCtl_Addr和Checksum)可以用来指明这个buffer的状态:

BufCtl xor Checksum=0xa110c8ed   –> 已分配内存
BufCtl xor Checksum=0xf4eef4ee    –> 已释放内存
BufCtl xor Checksum=其他             –> Memory Corruption!!

> 809e080^a919286d=X
                a110c8ed    –>所以malloc(50)所申请的内存处于已分配状态

 

 

再来看0x809e080所指向的umem_bufctl_audit数据结构 ,在/usr/include/umem_impl.h中的定义如下:

typedef struct umem_bufctl_audit {
        struct umem_bufctl      *bc_next;       /* next bufctl struct */
        void                          *bc_addr;       /* address of buffer  */
        struct umem_slab        *bc_slab;       /* controlling slab     */
        umem_cache_t           *bc_cache;     /* controlling cache  */
        hrtime_t                bc_timestamp;     /* transaction time */
        thread_t                    bc_thread;      /* thread doing transaction */
        struct umem_bufctl     *bc_lastlog;    /* last log entry */
        void                       *bc_contents;   /* contents at last free */
        int                           bc_depth;       /* stack depth */
        uintptr_t                  bc_stack[1];    /* pc stack */
} umem_bufctl_audit_t;

 

 

其实在mdb中就可以直接查看该数据结构:
> 809e080$<umem_bufctl_audit
{
    bc_next = 0
    bc_addr = 0x809cf80
    bc_slab = 0x809df98
    bc_cache = 0x808fa90
    bc_timestamp = 0xcbb4f7987e402
    bc_thread = 0×1
    bc_lastlog = 0x806f000
    bc_contents = 0
    bc_depth = 0×6
    bc_stack = [ 0xfef69ab4 ]
}

 

 

下面来看看malloc(100)所对应的内存:

> 80a0f80/32X
0x80a0f80: deadbeef        deadbeef        deadbeef        deadbeef        deadbeef
                deadbeef        deadbeef        deadbeef        deadbeef        deadbeef
                deadbeef        deadbeef        deadbeef        deadbeef        deadbeef
                deadbeef        deadbeef        deadbeef        deadbeef        deadbeef
                deadbeef        deadbeef        deadbeef        deadbeef        deadbeef
                deadbeef        deadbeef        deadbeef        feedface        feedface
                80a1100         fce4e5ee

 

 

可见释放后的内存被填充0xdeadbeef,redzone被填充0xfeedface 0xfeedface。

> 80a1100^fce4e5ee=X
                f4eef4ee  –> 表明这块buffer的状态是freed。

 

 

再看这个例子,如果我显式的把分配的内存初始化为0×00:

p = (int*)malloc(104);
memset(p,0,104);

> 80a0f80/32X
0x80a0f80: 70              3a10bf90        0               0               0
                0                   0               0               0               0
                0                   0               0               0               0
                0                   0               0               0               0
                0                   0               0               0               0
                0                   0               0        feedfabb        6dd1
                80a1100     a91ad9ed

 

 

注意这里user data section正好104字节,全部被初始化为0×00。于是0xbb被放到了redzone的第一个字节,0xfeedface变成了0xfeedfabb。104字节的user data是umem_alloc_112的极限,当试图malloc(105)的时候,就会使用umem_alloc_128了。

好了,数据结构基本上介绍完了,下一篇我会介绍如何发现memory leak。

 

 

你可能感兴趣的:(使用libumem定位memory leak和memory corruption(2))