【发布时间】:2014-11-25 08:33:47
【问题描述】:
我正在使用 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 仍然能够发现“无效写入”错误。
正在编译有问题的应用程序以及其他软件包,其中包含用于 MIPS 处理器 (uclibc v0.9.29) 的 uclibc-gcc 工具链,以闪存到运行 busybox (v1.17.2) linux shell 的嵌入式设备上.我直接在设备上运行 valgrind。我在启动 Valgrind 时使用以下选项:
--tool=memcheck --leak-check=full --undef-value-errors=no --trace-children=yes
基本上,即使我使用了堆,Valgrind 也不会检测到任何堆使用情况。为什么会这样?我的任何假设(如下)是错误的吗?
我的尝试
简单的测试程序
我从 Valgrind quick-start tutorial 编译了简单的测试程序(使用与上述应用程序相同的目标和工具链),以查看 Valgrind 是否会检测到泄漏。最终输出与上面相同:没有使用堆。
链接问题?
Valgrind 文档在 their FAQ 上有以下说明:
如果您的程序是静态链接的,大多数 Valgrind 工具只有在能够用自己的版本替换某些函数(例如 malloc)时才能正常工作。默认情况下,不会替换静态链接的 malloc 函数。这方面的一个关键指标是 Memcheck 是否说“所有堆块都已释放 - 没有泄漏是可能的”。
上面听起来和我的问题一模一样,所以我检查了它是否动态链接到包含malloc 和free 的C 库。我使用了 uclibc 工具链的自定义 ldd 可执行文件 (I can't use the native 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 的引用是未定义的(这是动态链接的可执行文件的特征)。
此外,我尝试按照常见问题解答的建议使用 --soname-synonyms=somalloc=NONE 选项启动 Valgrind。
LD_PRELOAD 支持?
正如评论者和回答者所指出的,Valgrind 取决于 LD_PRELOAD 的使用。有人建议我的工具链不支持此功能。为了确认确实如此,我按照this example 创建了一个简单的测试库并加载它(我将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
【问题讨论】:
-
您是否提供了 --trace-children=yes 选项?因为如果你使用 exec,你必须把那个选项
-
@yakoudbz 我最初没有使用该选项,但我现在使用了,结果没有改变。谢谢你的建议。我已经编辑了帖子以显示我正在使用的选项。
-
我记得一个类似的问题,即 uClibC 没有使用 LD_PRELOAD 支持构建,而 Valgrind 依赖于它。你能测试一下这是不是你的问题吗?如果是这样,在构建 uClibC 时启用 LD_PRELOAD 支持应该可以解决问题。
-
一个可能的原因可能是重定向机制没有将 malloc 调用重定向到 valgrind 拦截,因为 uclibc soname 不是预期的名称。如果是这种情况,请使用 --soname-synonyms=somalloc=xxxxxx 其中 xxxxxx 是 uclibc 库的 soname
-
您是否尝试创建一个您更确定会造成泄漏的虚拟程序,只是为了验证 Valgrind 也无法看到这一点?我注意到 Valgrind 对 MIP32 的支持是非常新的,也许有问题。但是,我确实期望 Valgrind 的质量,所以这似乎不太可能。
标签: c memory-management memory-leaks mips valgrind