我正在使用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
总堆使用量不能为零--应用程序中有许多许多次对malloc
和free
的调用。 Valgrind仍然可以找到“无效写入”错误。
所涉及的应用程序正在使用uclibc-gcc工具链(uclibc v0.9.29)与其他软件包一起编译,以便在运行busybox(v1.17.2)Linux shell的嵌入式设备上刷入MIPS处理器。我直接在设备上运行Valgrind。启动Valgrind时,我使用以下选项:
--tool=memcheck --leak-check=full --undef-value-errors=no --trace-children=yes
基本上,Valgrind没有检测到任何堆使用情况,尽管我已经使用了堆。这可能是为什么?我的以下假设是否有误?
我尝试过的方法
简单测试程序
我编译了Valgrind 快速入门教程中提供的简单测试程序(使用与上面应用程序相同的目标和工具链),以查看Valgrind是否会检测到泄漏。最终输出与上面相同:没有堆使用。
链接问题?
Valgrind文档在FAQ中有以下说明:
如果您的程序是静态链接的,则大多数Valgrind工具只有在能够替换某些函数(例如malloc)为其自己的版本时才能正常工作。默认情况下,不会替换静态链接的malloc函数。一个关键的指标是,如果Memcheck说“所有堆块都被释放 - 不可能有泄漏”。
以上听起来就像我的问题一样,所以我检查了它是否动态链接到包含malloc
和free
的C库。我使用了uclibc工具链的自定义ldd
可执行文件(我不能使用本地linux的ldd
),输出包括以下行:
libc.so.0 => not found (0x00000000)
/lib/ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x00000000)
因为我正在x86主机设备上运行,而mips目标设备没有ldd可执行文件,所以它们找不到。
根据我的理解,malloc
和free
将在其中一个库中,并且它们似乎是动态链接的。我还对可执行文件进行了readelf
和nm
操作,确认对malloc
和free
的引用未定义(这是动态链接可执行文件的特征)。
此外,我尝试使用FAQ建议的--soname-synonyms=somalloc=NONE
选项启动Valgrind。
正如评论员和回答者所指出的,Valgrind依赖于LD_PRELOAD的使用。有人建议我的工具链不支持此功能。为了确认它是否支持,我按照这个示例创建了一个简单的测试库并加载它(我用一个只返回42的函数代替了rand()
)。测试成功,因此看来我的目标完全支持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