Valgrind 在不同主机上运行在相同的 docker 镜像中,报告其中一个泄漏,但另一个没有泄漏

问题描述 投票:0回答:1

我们正在使用 docker devcontainers 进行开发。

容器运行 Ubuntu 22.04、gcc-11.3 和 valgrind-3.18.1

我们通过 valgrind 运行我们的单元测试以检查泄漏等,使用以下命令:

/usr/bin/valgrind \
    -v \
    --leak-check=full \
    --show-leak-kinds=definite,indirect,possible \
    --num-callers=50 \
    --track-origins=yes \
    --error-exitcode=1 \
        /src/.build/release/utils/test/foo_unit_test

单元测试使用嵌入式python,并在最后调用

Py_Finalize()
清理python分配。

GTEST_API_ int main(int argc, char** argv)
{
    testing::InitGoogleTest(&argc, argv);
    int res = RUN_ALL_TESTS();
    Py_Finalize();                          // clean up python allocations
    return res;
}

我们公司为员工工作站使用 aws workspaces,所以我们在 Amazon Linux 2 上运行我们的 devcontainer;报告如下:

$ lsb_release 
LSB Version:    :core-4.1-amd64:core-4.1-noarch

$ uname -a
Linux workstation 5.15.93-55.139.amzn2.x86_64 #1 SMP Tue Feb 14 21:47:11 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

在上述 Amazon Linux 2 主机上的 Ubuntu 22.04 docker 容器中运行上述 valgrind 命令,没有泄漏报告。

但是,我们也有一个自托管的 CI 构建服务器,它运行 Ubuntu 22.04 作为主机操作系统;报告如下:

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"

$ uname -a
Linux build_server 5.15.0-48-generic #54~20.04.1-Ubuntu SMP Thu Sep 1 16:17:26 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

在构建服务器上的同一 Ubuntu 22.04 docker 容器中运行相同的 valgrind 命令会报告以下泄漏:

==333== HEAP SUMMARY:
==333==     in use at exit: 647,380 bytes in 299 blocks
==333==   total heap usage: 265,491 allocs, 265,192 frees, 85,629,984 bytes allocated
==333== 
==333== Searching for pointers to 299 not-freed blocks
==333== Checked 18,296,672 bytes
==333== 
==333== 568 bytes in 1 blocks are possibly lost in loss record 28 of 169
==333==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==333==    by 0x4AAAEB8: _PyObject_GC_Malloc (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x4AAB1EB: _PyObject_GC_NewVar (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
...
==333==    by 0x4A6B1FD: PyImport_ImportModule (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x4A45E6C: _PyCodec_Lookup (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x4A808AE: Py_InitializeFromConfig (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x4A82C1B: Py_InitializeEx (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)

==333== 664 bytes in 1 blocks are possibly lost in loss record 77 of 169
==333==    at 0x484DCD3: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==333==    by 0x4AA6238: _PyObject_GC_Resize (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x48F362D: _PyEval_EvalFrameDefault (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
...
==333==    by 0x4961EB5: _PyObject_FastCallDictTstate (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x496204F: _PyObject_Call_Prepend (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)
==333==    by 0x496222B: _PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython3.10.so.1.0)

etc...

==333== LEAK SUMMARY:
==333==    definitely lost: 0 bytes in 0 blocks
==333==    indirectly lost: 0 bytes in 0 blocks
==333==      possibly lost: 2,728 bytes in 4 blocks
==333==    still reachable: 644,652 bytes in 295 blocks
==333==         suppressed: 0 bytes in 0 blocks
==333== Reachable blocks (those to which a pointer was found) are not shown.
==333== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==333== 
==333== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
  • 我认为 Valgrind 在 malloc 等上做了一个

    LD_PRELOAD
    ,这在两台机器上肯定是相同的,因为它们运行相同的版本,那么为什么在运行相同的 docker 容器中运行相同的代码时我会得到不同的结果不同的主机?

  • 无需诉诸压制,我能做些什么来确保释放此内存并且 valgrind 认为这不是可能的泄漏?

c++ docker memory-leaks valgrind
1个回答
0
投票

如果你修复了 295 漏洞,那么它们将不再被报告。好吧,这不是很有帮助。如果一个配置泄漏而不是另一个配置泄漏,那么他们正在做一些不同的事情。您需要进行一些并行调试,以查看一个正在释放内存的位置以及另一个没有释放内存的原因。

您可能会看到平台之间在检测“可能”和“确定”泄漏方面存在一些差异。两者之间的区别在于,在程序退出时,memcheck 会搜索内存并注册指向泄漏块的指针。如果它找到一个指向块的起点的指针,则将其计为“正在使用”,如果它找到一个指向块内部某处的指针,则将其计为“潜在”,如果找不到指向该块的指针,则为它'确定'。

“可能的”泄漏通常是由随机值或剩余物或诸如内存池或分配器之类的东西引起的,这些分配器会在分配的内存的开头添加一个 redzone 或 lngth 并在之后返回地址。

最后,Valgrind 没有使用 LD_PRELOAD 来代替 malloc。它拦截对

mmap
的系统调用。当它是一个文件时,它会查看该文件,并且它是一个 ELF 共享库(或 macOS 上的 macho 共享库),它将触发读取 DWARF 调试信息和函数重定向。当它看到 malloc 和 family 时,它只是用自己的拦截替换函数指针。对于与静态 libc 链接的 exe,当使用相同的机制加载 exe 时,上述所有操作都会完成。

© www.soinside.com 2019 - 2024. All rights reserved.