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

Memory Corruption

今天介绍memory corruption的处理,往往在程序中会发生SEGMENMT FAULT, ARRAY BOUND WRITER,DOUBLE-FREE等等,处理以来很麻烦,这里先给一个教科书级别的例子,实际中的情况要复杂很多,特别是在多线程的时候更麻烦。

int *p = (int*)malloc(16);
for(int i=0; i<= 4;i++)     p[i]=0;

> ::umem_verify
Cache Name                      Addr         Cache Integrity
umem_magazine_1              8087010     clean
umem_magazine_3              8087390     clean

umem_alloc_24                   808c710     1  corrupt buffer

umem_verify会检查所有在umem管辖之下的内存的完整性(integrity),我还不知道umem_verify的算法,希望有知道的人能够帮助我理解,因为我在实际使用中有发现memory已经corrupt了,但是verify还是报clean的。上面检查出来umem_alloc_24所管辖的内存中,有一个buffer是corrupted buffer,改cache的地址是0x808c710:
> 808c710::umem_verify
Summary for cache ‘umem_alloc_24′
  buffer 809cfd0 (allocated) has a corrupt redzone size encoding    //–>这里给出了更详尽的信息

上面的0x809cfd0就是buffer的地址,我们来看一下:

> 809cfd0/10X
0x809cfd0: 18           3a10bfe8        0                   0                     0
                0                0                1789            80a2e30         a91ae6dd

> 80a2e30^a91ae6dd=X
                a110c8ed
> 1789=D
                6025     // (6025-1)/251 – 8 =16 分配了16字节
注意到我们没有看到feedface,那是redzone的标志,还好redzone的第二个字节并没有被破坏。在user data中一共有5个4字节被初始化为0了,但是应该只分配了4个4字节,所有最后一个4字节是指针越界了。这一点808c710::umem_verify已经告诉我们了。但是注意,这个时候程序并没有崩溃,往往就是这样的,这个时候程序埋下了一个地雷,要之后后面有人去踩了这个地雷,问题才会爆发,所以一般情况下程序奔溃的时候我们看到的call stack并不是问题发生的第一现场,这一点要牢记!

还有在程序出问题的时候,libumem会把最后的出错信息保存下来,我们可以通过::umem_status来查看:

> ::umem_status
Status:         ready and active
Concurrency:    8
Logs:           transaction=128k
Message buffer:    –>注意到这个时候虽然mmeory已经corruption了,但是umem_status什么错误也没有留下。

我现在把程序稍微改一下:
int *p = (int*)malloc(16);
free(p);
free(p);
for(int i=0; i<=4;i++)    p[i]=0;

-bash-3.00$ UMEM_DEBUG=default UMEM_LOGGING=transaction LD_PRELOAD=libumem.so.1 ./Test &
[1] 5571
-bash-3.00$
[1]+  Abort                   (core dumped) UMEM_DEBUG=default UMEM_LOGGING=transaction LD_PRELOAD=libumem.so.1 ./Test

这次程序崩溃了,于是我们分析一下core 文件:

-bash-3.00$ mdb core
Loading modules: [ libumem.so.1 libc.so.1 ld.so.1 ]
> $C
080475f0 libc.so.1`_lwp_kill+7(1, 6)
08047608 libc.so.1`raise+0x1f(6)
08047618 libumem.so.1`umem_do_abort+0×25(0, fef85000, 8047654, fef67b8a, fef72f3c, fef89a00)
08047628 libumem.so.1`umem_err_recoverable+0×46(fef72f3c, fef89a00, 809cfd8, fef72f64)
08047654 libumem.so.1`process_free+0×82(809cfd8, 1, 0, 80476ac, 8050995, 809cfd8)
08047668 libumem.so.1`free+0×14(809cfd8, 8060a3c, 8047694, 8047760)
080476ac main+0×45(1, 80476d8, 80476e0)
080476cc _start+0×80(1, 80477c8, 0, 80477cf, 80477e2, 80477fa)

我们看到是free的时候出了错,抛出了异常,然后由abort导致程序崩溃。下面我按部就班的用上面介绍的方法试一下:

> ::umem_status
Status:         ready and active
Concurrency:    8
Logs:           transaction=128k
Message buffer:
free(809cfd8): double-free or invalid buffer  //这次umem_status帮了忙,告诉我很有可能是double-free造成的
stack trace:
libumem.so.1′?? (0xfef66099)
libumem.so.1′?? (0xfef67b8a)
libumem.so.1′free+0×14
Test’main+0×45
Test’_start+0×80

> ::umem_verify ! grep corrupt
>                                             //注意这里,umem_verify认为所有的memory都是clean的!!这一点跟我的想象有点出入

> 809cfd8::whatis
809cfd8 is 809cfd0+8, bufctl 80a2e30 freed from umem_alloc_24
> 809cfd0/10X
0x809cfd0: deadbeef        deadbeef       deadbeef        deadbeef        deadbeef
                deadbeef        feedface        feedface        80a2e30         fce4dade
> 80a2e30^fce4dade=X
                f4eef4ee

这下理解为什么umem_verify认为都是 clean的了,确实是clean的嘛,这块内存好好的。

> ::umalog

T-0.000000000  addr=809cfd0  umem_alloc_24
         libumem.so.1`umem_cache_free_debug+0×135
         libumem.so.1`umem_cache_free+0x3f
         libumem.so.1`umem_free+0xd5
         libumem.so.1`process_free+0xfd
         libumem.so.1`free+0×14
         main+0×37
         _start+0×80

T-0.000008164  addr=809cfd0  umem_alloc_24
         libumem.so.1`umem_cache_alloc_debug+0x16c
         libumem.so.1`umem_cache_alloc+0x15c
         libumem.so.1`umem_alloc+0x3f
         libumem.so.1`malloc+0×23
         main+0×26
         _start+0×80

注意到umalog只显示了两次memory 分配释放的记录,也就是说最后那次free操作并没有被记录下来。所以我的理解是,失败的内存操作不会被logging,但是我们可以通过查看umem_status得到最后出错的原因。

最后我想说的是,最好要好好学习一下mdb。网上还有一些比较好的资源:

http://blogs.sun.com/jwadams/entry/debugging_with_libumem_and_mdb 这是libumem的作者的blog。
http://reader.feedshow.com/show_items-feed=9d02698904f608e3444e87df42a7ac8a

昨天早上给组里的同事做了个讲座,介绍这些技巧的。Manager倒是挺鼓励我的,一是希望我翻译成英文,这样美国那边的同事也可以看看,二是希望能够平时多积累解决实际问题的经验,和美国那边的同事分享,这样对自己,对整个CDC SBE都有益处。

最近还在查另外一个memory tracking的问题,我基本上已经确定不是memory leak的问题,接下来就是要找出来是谁不停得问系统要资源,我觉得dtrace帮了我大忙,再接再厉,希望能够尽快找出来问题的根源。

 

你可能感兴趣的:(manager,cache,buffer,logging,leak,encoding)