对应github: https://github.com/luochenglcs/libumem
1
2
3
4
reference:
https://arrowpig1979.wordpress.com/2008/08/16/%e4%bd%bf%e7%94%a8libumem%e5%ae%9a%e4%bd%8dmemory-leak%e5%92%8cmemory-corruption%ef%bc%884%ef%bc%89/
https://www.codenong.com/8287649/
一、libumem介绍
libumem是一个运行在用户模式的内存分配程序库,包含在Solaris 9及以后的版本中。libumem不仅能够优化程序的内存分配,而且还提供了内存分配调试和记录的功能,配合mdb工具,可以轻松观察程序内存的分配情况和定位内存泄漏的问题。
libumem使用Slab概念。Slab是Slab Allocator中一个基本内存单元,代表一个或者多个虚拟内存中的页(Page),通常会被分割成为多个大小等同的Chunks,即Buffer。Buffer含有用户所使用的数据,以及一些额外的信息(取决于环境变量的设置)。这些额外的信息对我们调试,检测内存泄漏非常有用。下面就是 Buffer 的一个基本结构:
1
2
3
4
Metadata Section,提供内存分配的长度信息,在32位程序应用中为8个字节。
User Data Section,用户使用的内存区域,存储用户数据。
Redzone Section,8个字节,隔离User Data和Debug Meta Data。
Debug Metadata,8个字节。前面四个字节为指针,指向一个umem_bufctl_audit结构,记录内存分配时候的堆栈。此结构的定义可以在/usr/include/umem_impl.h找到。后面的四个字节为校验位,与前面字节一起来判断这个buffer是否被破坏。
https://hosam.wordpress.com/opensolaris-open-source-from-sun-microsystems-inc/
二、libumem的维测特性
1 linux目前的内存调测手段
1
2
3
4
5
6
7
8
1.glibc内存检测
2.valgrind内存检查机制
3、gperftools内存检查机制
4、ASan内存检查机制
5、Memwatch内存检查机制
6、Dr.Memory内存检查机制
9、Electric Fence内存检查机制
8、Dmalloc内存检查机制
2 libumem的内存调测
需要和mdb工具配合,
我们先看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void test_leak_malloc(void)
{
char *p = malloc(50);
p = malloc(100);
free(p);
}
void test_UAF(void)
{
char *p = malloc(50);
free(p);
*p = 1;
}
void main(void)
{
char *p = malloc(50);
test_leak_malloc();
test_UAF();
pause();
return;
}
gcc -g test.c -o test
UMEM_DEBUG=default, UMEM_LOGGING=transaction LD_PRELOAD=/usr/local/lib/libumem.so.0 ./test&
//使用 man umem_debug查看UMEM_DEBUG、UMEM_LOGGING的含义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[root@localhost ~]# mdb -p `pidof test` //使用mdb attach到test进程
loading modules: [ libgcc_s-8-20191121.so.1 libdl-2.28.so libpthread-2.28.so libc-2.28.so libumem.so.0.0.0 ld-2.28.so ]
::findleaks -d
BYTES LEAKED VMEM_SEG CALLER
16384 6 7f3daf3af000 MMAP
4096 1 7f3db1c40000 MMAP
8192 1 7f3db1c3c000 MMAP
8192 1 7f3db1c28000 MMAP
33595392 1 7f3dafa0c000 MMAP
16384 1 7f3daf771000 MMAP
------------------------------------------------------------------------
Total 6 oversized leaks, 33648640 bytes
CACHE LEAKED BUFCTL CALLER
00007f3db1bba048 1 00007f3db1b3e7e0 main+0x12 //内存泄漏1
00007f3db1bba048 1 00007f3db1b3e8c0 test_leak_malloc+0x12 //内存泄漏2
------------------------------------------------------------------------
Total 2 buffers, 160 bytes
mmap(2) leak: [7f3daf3af000, 7f3daf3b3000), 16384 bytes
mmap(2) leak: [7f3db1c40000, 7f3db1c41000), 4096 bytes
mmap(2) leak: [7f3db1c3c000, 7f3db1c3e000), 8192 bytes
mmap(2) leak: [7f3db1c28000, 7f3db1c2a000), 8192 bytes
mmap(2) leak: [7f3dafa0c000, 7f3db1a16000), 33595392 bytes
mmap(2) leak: [7f3daf771000, 7f3daf775000), 16384 bytes
umem_alloc_80 leak: 1 buffer, 80 bytes
ADDR BUFADDR TIMESTAMP THREAD
CACHE LASTLOG CONTENTS
7f3db1b3e7e0 7f3db1b6bf60 60116209000b4637 -1312650368
7f3db1bba048 7f3db1bf8300 0
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39 //泄漏内存的申请流程
main+0x12
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
umem_alloc_80 leak: 1 buffer, 80 bytes
ADDR BUFADDR TIMESTAMP THREAD
CACHE LASTLOG CONTENTS
7f3db1b3e8c0 7f3db1b6bef0 60116209000b463c -1312650368
7f3db1bba048 7f3db1bf83c0 0
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39
test_leak_malloc+0x12 //泄漏内存的申请流程
main+0x1b
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
通过findleaks -d可以查看到内存泄漏的调用栈和信息;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
T-0.000000000 addr=7f3db1b6be80 umem_alloc_80 //test_UAF free addr=7f3db1b6be80
test_UAF+0x22
main+0x20
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
T-0.000000005 addr=7f3db1b6be80 umem_alloc_80 //test_UAF malloc(50) addr=7f3db1b6be80
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39
test_UAF+0x12
main+0x20
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
T-0.000000060 addr=7f3db1b6af40 umem_alloc_128 //test_leak_malloc free addr=7f3db1b6af40
test_leak_malloc+0x30
main+0x1b
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
T-0.000000067 addr=7f3db1b6af40 umem_alloc_128 //test_leak_malloc malloc(100) addr=7f3db1b6af40
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39
test_leak_malloc+0x20
main+0x1b
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
T-0.000000182 addr=7f3db1b6bef0 umem_alloc_80 //test_leak_malloc malloc(50) addr=7f3db1b6bef0
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39
test_leak_malloc+0x12
main+0x1b
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
T-0.000000187 addr=7f3db1b6bf60 umem_alloc_80 //main malloc(50) addr=7f3db1b6bf60
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39
main+0x12
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
通过umalog命令可以看到具体分配的细节;
从上面也可以看到有两处申请未释放。
memory corruption的处理;通过memory corruption的有user after free, double free, array bound write…
1
2
3
4
5
6
::umem_verify
Cache Name Addr Cache Integrity
...
umem_alloc_80 7f3db1bba048 1 corrupt buffer
umem_alloc_96 7f3db1bb9048 clean
...
7f3db1bba048::umem_verify
Summary for cache 'umem_alloc_80'
buffer 7f3db1b6be80 (free) seems corrupted, at 7f3db1b6be90 //这里已经free的7f3db1b6be80地址出现corrupted
通过上面umalog命令可以查看到申请的调用栈:
1
2
3
4
5
6
7
T-0.000000005 addr=7f3db1b6be80 umem_alloc_80 //test_UAF malloc(50) addr=7f3db1b6be80
libumem.so.0.0.0`umem_alloc+0x98
libumem.so.0.0.0`malloc+0x39
test_UAF+0x12
main+0x20
libc-2.28.so`__libc_start_main+0xf3
_start+0x2e
综合信息可以知道test_UAF中出现use after free的情况;
ps:目前libumem支持调用栈的getstack的代码还没有合入; 后面需要合入社区代码还有很多待完善的地方。