Woo*_*low 20 c valgrind memory-leaks memory-management mips
我正在使用valgrind(v3.10.0)来寻找复杂应用程序(一个经过大量修改的net-snmp版本)中的内存泄漏,该应用程序是作为更大的软件套件的一部分构建的.我确信存在泄漏(应用程序的内存占用量无限制地线性增长),但valgrind总是在终止时报告以下内容.
==1139== HEAP SUMMARY:
==1139== in use at exit: 0 bytes in 0 blocks
==1139== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1139==
==1139== All heap blocks were freed -- no leaks are possible
Run Code Online (Sandbox Code Playgroud)
总堆的使用不能为零-还有很多,很多电话malloc和free整个应用程序.Valgrind仍然能够找到"无效写入"错误.
正在编译该应用程序以及其他软件包,其中MIPS处理器的uclibc-gcc工具链(uclibc v0.9.29)将被闪存到运行busybox(v1.17.2)linux shell的嵌入式设备上.我正在设备上直接运行valgrind.我在启动Valgrind时使用以下选项:
--tool=memcheck --leak-check=full --undef-value-errors=no --trace-children=yes
Run Code Online (Sandbox Code Playgroud)
基本上,即使我使用了堆,Valgrind也没有检测到任何堆使用情况.为什么会这样?我的任何假设(下面)都是错误的吗?
我从Valgrind 快速入门教程编译了简单的测试程序(使用与上面的应用程序相同的目标和工具链),以查看Valgrind是否会检测到泄漏.最终输出与上面相同:没有堆使用.
Valgrind文档在他们的FAQ上有如下说明:
如果您的程序是静态链接的,那么大多数Valgrind工具只有在能够用自己的版本替换某些功能(例如malloc)时才能正常工作.默认情况下,不替换静态链接的malloc函数.一个关键的指标是,如果Memcheck说"所有堆块都被释放 - 没有泄漏是可能的".
上面的声音与我的问题完全一样,所以我检查它是否动态链接到包含malloc和的C库free.我使用了uclibc工具链的自定义ldd可执行文件(我不能使用原生linuxldd),输出包括以下几行:
libc.so.0 => not found (0x00000000)
/lib/ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x00000000)
Run Code Online (Sandbox Code Playgroud)
(找不到它们的原因是因为我在x86主机设备上运行它; mips目标设备没有ldd可执行文件.)根据我的理解,malloc并且free将在其中一个库中,并且它们似乎是动态链接的.我也没有readelf和nm对可执行文件,以确认该引用malloc和free是不确定的(这是一个动态链接的可执行文件的特性).
此外,我尝试--soname-synonyms=somalloc=NONE按照FAQ的建议启动Valgrind .
正如评论者和回答者所指出的,Valgrind依赖于LD_PRELOAD的使用.有人建议我的工具链不支持此功能.为了确认它,我按照这个例子创建了一个简单的测试库并加载它(我rand()用一个只返回42的函数替换).测试工作,所以看起来我的目标支持LD_PRELOAD就好了.
我还将从readelf命令中包含一些可能有用的信息.而不是一个巨大的转储,我已经削减了一些东西,只包括可能相关的东西.
Dynamic section
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libnetsnmpagent.so.30]
0x00000001 (NEEDED) Shared library: [libnetsnmpmibs.so.30]
0x00000001 (NEEDED) Shared library: [libnetsnmp.so.30]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.0]
0x0000000f (RPATH) Library rpath: [//lib]
Symbol table '.dynsym'
Num: Value Size Type Bind Vis Ndx Name
27: 00404a40 0 FUNC GLOBAL DEFAULT UND free
97: 00404690 0 FUNC GLOBAL DEFAULT UND malloc
Run Code Online (Sandbox Code Playgroud)
abl*_*igh 10
首先,让我们做一个真正的测试,看看是否有静态链接.
$ ldd -v /bin/true
linux-vdso.so.1 => (0x00007fffdc502000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0731e11000)
/lib64/ld-linux-x86-64.so.2 (0x00007f07321ec000)
Version information:
/bin/true:
libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6:
ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
Run Code Online (Sandbox Code Playgroud)
输出中的第二行显示它是动态链接到的libc,它包含的内容malloc.
至于可能出现的问题,我可以建议四件事:
也许它与正常情况无关libc,但与某些其他C库(例如uclibc)或其他东西valgrind没有预料到.上述测试将准确显示与之相关的内容.为了valgrind工作,它用于LD_PRELOAD包装malloc()和free()函数(这里包含一般函数的描述).如果您的libc替代品不支持LD_PRELOAD或(某种方式)C库malloc()并且free()根本没有使用(使用这些名称),那么valgrind就不会起作用.也许您可以包含构建应用程序时使用的链接行.
它正在泄漏,但它没有使用分配内存malloc().例如,它可能(不太可能)进行自己的调用brk(),或者(更有可能)分配内存mmap.你可以用它来找出(这是一个cat自己的转储).
.
$ cat /proc/PIDNUMBERHERE/maps
00400000-0040b000 r-xp 00000000 08:01 805303 /bin/cat
0060a000-0060b000 r--p 0000a000 08:01 805303 /bin/cat
0060b000-0060c000 rw-p 0000b000 08:01 805303 /bin/cat
02039000-0205a000 rw-p 00000000 00:00 0 [heap]
7fbc8f418000-7fbc8f6e4000 r--p 00000000 08:01 1179774 /usr/lib/locale/locale-archive
7fbc8f6e4000-7fbc8f899000 r-xp 00000000 08:01 1573024 /lib/x86_64-linux-gnu/libc-2.15.so
7fbc8f899000-7fbc8fa98000 ---p 001b5000 08:01 1573024 /lib/x86_64-linux-gnu/libc-2.15.so
7fbc8fa98000-7fbc8fa9c000 r--p 001b4000 08:01 1573024 /lib/x86_64-linux-gnu/libc-2.15.so
7fbc8fa9c000-7fbc8fa9e000 rw-p 001b8000 08:01 1573024 /lib/x86_64-linux-gnu/libc-2.15.so
7fbc8fa9e000-7fbc8faa3000 rw-p 00000000 00:00 0
7fbc8faa3000-7fbc8fac5000 r-xp 00000000 08:01 1594541 /lib/x86_64-linux-gnu/ld-2.15.so
7fbc8fca6000-7fbc8fca9000 rw-p 00000000 00:00 0
7fbc8fcc3000-7fbc8fcc5000 rw-p 00000000 00:00 0
7fbc8fcc5000-7fbc8fcc6000 r--p 00022000 08:01 1594541 /lib/x86_64-linux-gnu/ld-2.15.so
7fbc8fcc6000-7fbc8fcc8000 rw-p 00023000 08:01 1594541 /lib/x86_64-linux-gnu/ld-2.15.so
7fffe1674000-7fffe1695000 rw-p 00000000 00:00 0 [stack]
7fffe178d000-7fffe178f000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Run Code Online (Sandbox Code Playgroud)
请注意结束地址[heap]是否实际增长,或者您是否看到其他mmap条目.是否valgrind有效的另一个好的指标是发送一个SIGSEGV或类似的进程,看看你是否在退出时看到堆正在使用.
它不是严格意义上的泄漏,而是泄漏到所有意图和目的.例如,它可能具有数据结构(如缓存),随着时间的推移而增长.退出时,程序(正确)释放缓存中的所有条目.因此,在退出时,堆上没有任何东西在使用.在这种情况下,您将想知道正在发展的是什么.这是一个更难的主张.我将使用该技术杀死程序(上图),捕获输出并对其进行后处理.如果您在24小时后看到500件事,48小时后看到1,000件,在72小时后看到1,500件,这应该可以告诉您什么是"泄漏".但是,正如haris在评论中指出的那样,虽然这会导致内存不会显示为泄漏,但它并不能解释"总堆使用率"为零,因为这描述了所做的和已释放的总分配.
也许valgrind只是没有在你的平台上工作.如果您构建一个非常简单的程序,如下所示,并valgrind在您的平台上运行,会发生什么?如果这不起作用,您需要找出为什么 valgrind不能正常运行.请注意,valgrind在MIPS上是非常新的.这是一个电子邮件主题,MIPS和uclibc发现的开发人员valgrind不会报告任何分配.他的解决办法是更换ntpl用linuxthreads.
.
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
void *p = malloc (100); /* does not leak */
void *q = malloc (100); /* leaks */
free (p);
exit (0);
}
Run Code Online (Sandbox Code Playgroud)