dmalloc检测MLK

来源:互联网 发布:北邮图书馆网络 编辑:程序博客网 时间:2024/06/09 20:23


1.从www.dmalloc.com下载一个rpm包(你也可以下载源码包,本人比较懒 :) )

2.安装

3.export DMALLOC_OPTIONS=log=logname,debug=0x3
注:logname是你要生成记录的文件名

4.在你需要检测的源代码里包含dmalloc.h
#include <dmalloc.h>

5.保存退出编译
gcc -ldmalloc -o program code.c

6../program
会在当前目录下生成一个logname,现在你就可以看到你的程序未释放的内存了
以下是我一个程序的生成的log:


1134286917: 23: Dmalloc version '5.4.2' from 'http://dmalloc.com/'
1134286917: 23: flags = 0x3, logfile 'logfile'
1134286917: 23: interval = 0, addr = 0, seen # = 0, limit = 0
1134286917: 23: starting time = 1134286917
1134286917: 23: process pid = 12088
1134286917: 23: WARNING: tried to free(0) from 'module.c:23'
1134286917: 27: WARNING: tried to free(0) from 'module.c:23'
1134286917: 27: Dumping Chunk Statistics:
1134286917: 27: basic-block 4096 bytes, alignment 8 bytes
1134286917: 27: heap address range: 0x111000 to 0x49c000, 3715072 bytes
1134286917: 27:     user blocks: 4 blocks, 16048 bytes (39%)
1134286917: 27:    admin blocks: 6 blocks, 24576 bytes (60%)
1134286917: 27:    total blocks: 10 blocks, 40960 bytes
1134286917: 27: heap checked 0
1134286917: 27: alloc calls: malloc 14, calloc 0, realloc 0, free 13
1134286917: 27: alloc calls: recalloc 0, memalign 0, valloc 0
1134286917: 27: alloc calls: new 0, delete 0
1134286917: 27:   current memory in use: 432 bytes (3 pnts)
1134286917: 27:  total memory allocated: 6204 bytes (14 pnts)
1134286917: 27:  max in use at one time: 4988 bytes (12 pnts)
1134286917: 27: max alloced with 1 call: 4124 bytes
1134286917: 27: max unused memory space: 4740 bytes (48%)
1134286917: 27: top 10 allocations:
1134286917: 27:  total-size  count in-use-size  count  source
1134286917: 27:        4124      1           0      0  ra=0x6e5910
1134286917: 27:         864      6           0      0  module.c:43
1134286917: 27:         432      3           0      0  module.c:133
1134286917: 27:         432      3         432      3  module.c:185
1134286917: 27:         352      1           0      0  ra=0x6b276d
1134286917: 27:        6204     14         432      3  Total of 5
1134286917: 27: Dumping Not-Freed Pointers Changed Since Start:
1134286917: 27:  not freed: '0x111400|s1' (144 bytes) from 'module.c:185'
1134286917: 27:  not freed: '0x111500|s1' (144 bytes) from 'module.c:185'
1134286917: 27:  not freed: '0x111600|s1' (144 bytes) from 'module.c:185'
1134286917: 27:  total-size  count  source
1134286917: 27:         432      3  module.c:185
1134286917: 27:         432      3  Total of 1
1134286917: 27: ending time = 1134286917, elapsed since start = 0:00:00


可以看到,在185行的代码分配的432个字节的内存未被释放,...............................over
 

Dmalloc是一款linux下诊断内存泄露的工具,安装使用步骤如下:

1 安装dmalloc

l         执行./configure --enable-threads

l         Make

l         Make install

l         dmalloc安装后的lib路径加入到/etc/ld.so.conf中,然后执行ldconfig –v

l         .bashrc, .profile.zshrc文件中添加function dmalloc { eval `/usr/local/bin/dmalloc -b $*`; }

2 使用dmalloc

l         执行 dmalloc -l logfile -i 100 low

l         在要检测程序中添加:

#ifdef DMALLOC

#include "dmalloc.h"

#endif

l         如果想在程序不退出时观察监测结构,需要在程序中使用函数

       dmalloc_debug_setup(getenv("DMALLOC_OPTIONS"));//初始化

       在需要监测的程序段的前后分别使用函数

mark = dmalloc_mark();

       dmalloc_log_changed(mark,1,0,1);

l         执行程序,在logfile中观察结果

3 根据结果分析数据

l         若在logfile中出现not freed: '0x400177c8|s1047' (20 bytes) from 'ra=0x0x400618' 则说明程序存在内存泄露;

l         定位内存泄露代码行数(使用命令readelf nm ldd

调试一个崩溃的程序的第一步是弄清哪里出了错

 

zSeries 上的 Linux 内核具有这样一个内置特性,它在用户进程崩溃时记录一些基本的调试信息。要启用这个特性,请以 root 用户身份执行如下命令:

 

 

echo 1 >> /proc/sys/kernel/userprocess_debug

 

 

当某个进程崩溃时,日志文件(/var/log/messages)中就会给出附加的信息,包括程序终止原因、故障地址,以及包含程序状态字(PSW)、通用寄存器和访问寄存器的简要寄存器转储。

 

 

Mar 31 11:34:28 l02 kernel: User process fault: interruption code 0x10

 

Mar 31 11:34:28 l02 kernel: failing address: 0

 

Mar 31 11:34:28 l02 kernel: CPU:    1

 

Mar 31 11:34:28 l02 kernel: Process simple (pid: 30122, stackpage=05889000)

 

Mar 31 11:34:28 l02 kernel:

 

Mar 31 11:34:28 l02 kernel: User PSW:    070dc000 c00ab738

 

Mar 31 11:34:28 l02 kernel: task: 05888000 ksp: 05889f08 pt_regs: 05889f68

 

Mar 31 11:34:28 l02 kernel: User GPRS:

 

Mar 31 11:34:28 l02 kernel: 00000000  004019a0  004019a0  00000000

 

Mar 31 11:34:28 l02 kernel: 00000003  c00ab732  004008f8  00400338

 

Mar 31 11:34:28 l02 kernel: 40018ffc  0040061c  40018e34  7ffff800

 

Mar 31 11:34:28 l02 kernel: 00400434  80400624  8040066e  7ffff800

 

Mar 31 11:34:28 l02 kernel: User ACRS:

 

Mar 31 11:34:28 l02 kernel: 00000000  00000000  00000000  00000000

 

Mar 31 11:34:28 l02 kernel: 00000001  00000000  00000000  00000000

 

Mar 31 11:34:28 l02 kernel: 00000000  00000000  00000000  00000000

 

Mar 31 11:34:28 l02 kernel: 00000000  00000000  00000000  00000000

 

Mar 31 11:34:28 l02 kernel: User Code:

 

Mar 31 11:34:28 l02 kernel: 44 40 50 00 07 fe a7 4a 00 01 18 54 18 43 18 35

 

a8 24 00 00

 

 

执行:readelf -l myproc

 

出现如下信息:

Elf file type is EXEC (Executable file)

Entry point 0x400474

There are 6 program headers, starting at offset 52

Program Headers:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align

  PHDR           0x000034 0x00400034 0x00400034 0x000c0 0x000c0 R E 0x4

  INTERP         0x0000f4 0x004000f4 0x004000f4 0x0000d 0x0000d R   0x1

      [Requesting program interpreter: /lib/ld.so.1]

  LOAD           0x000000 0x00400000 0x00400000 0x00990 0x00990 R E 0x1000

  LOAD           0x000990 0x00401990 0x00401990 0x000fc 0x00114 RW  0x1000

  DYNAMIC        0x0009ac 0x004019ac 0x004019ac 0x000a0 0x000a0 RW  0x4

  NOTE           0x000104 0x00400104 0x00400104 0x00020 0x00020 R   0x4

Program Headers 部分,第一个 LOAD 行提供了关于程序从哪里加载的信息。在 Flg 列,该段被标记为 R(read)E(executable)VirtAddr 是程序开始加载的地址。MemSiz 是正在被加载到这个段中的代码长度。把它加到 VirtAddr 上,这个程序的基本地址范围就是 0x400000-0x400990程序发生崩溃的指令地址为 0x400618,在程序的加载范围之内。现在我们知道了问题直接发生在代码中。

 

执行 addr2line -e simple 0x400618

 

出现如下信息

/home/devuser/myproc.c:34,则说明问题出在myproc.c的第34行。

若出错地址不再程序地址中,如为0x400ab738。这个地址并不准确地落在我们的小程序之内。那么,它是什么呢?是来自共享库的代码。如果对可执行文件运行 ldd 命令(ldd myproc),将会返回程序运行所需的共享对象的列表,以及该库在那里可用的地址,如下所示

libc.so.6 => /lib/libc.so.6 (0x40021000)

/lib/ld.so.1 => /lib/ld.so.1 (0x40000000)

所以该指令地址对应于加载 libc.so.6 的地址,现在我们来确定崩溃发生在 libc 中的何处。假设 libc.so.6 的加载地址是 0x40021000,从指令地址 0x400ab738 减去它,结果为 0x8a738。这是进入 libc.so.6 的偏移。使用 nm 命令,从 libc.so.6 转储符号,然后尝试确定该地址位于哪个函数中。对于 libc.so.6nm 将生成 7,000 多行输出。通过对计算得出的偏移部分执行 grep(正则表达式查找程序)可以削减必须检查的数据量。输入:

 

nm /lib/libc.so.6 | sort | grep 0008a

 

将返回 66 行,在该输出的中间,我们会发现:

 

 

0008a6fc T memcpy

 

0008a754 t _wordcopy_fwd_aligned

 

 

  该偏移落在 memcpy 中的某个位置。在此例中,一个空指针被当作目标地址传递给了 memcpy。我们在何处调用的 memcpy 呢?问得好。我们可以通过检查输出在日志文件中的寄存器转储来确定目标区域。寄存器 14 包含执行某个函数调用时的返回地址。根据 1R14 0x8040066e,它在截去高位之后产生一个地址 0x40066e。这个地址落在我们的程序范围之内,因此可以运行 addr2line 来确定该地址在何处。输入:

 

addr2line -e myproc 0x40066e

 

将返回:

 

/home/devuser/myproc.c:36

 

这是我们调用 memcpy 之后的那一行。

 

 

 

 

 

 

 

原创粉丝点击