c++ Memchk(valgrind)报告不同Docker主机中的结果不一致

6tdlim6h  于 2023-02-01  发布在  Docker
关注(0)|答案(2)|浏览(170)

我有一个相当健壮的C++库CI测试,这些测试(大约50个)运行在相同的Docker映像上,但在不同的机器上。
在一台机器(“A”)中,所有memcheck(valgrind)测试均通过(即没有内存泄漏)。在另一台机器(“B”)中,* 所有 * 测试均产生以下相同的valgrind错误。

51/56 MemCheck #51: combinations.cpp.x ....................***Exception: SegFault  0.14 sec
valgrind: m_libcfile.c:66 (vgPlain_safe_fd): Assertion 'newfd >= VG_(fd_hard_limit)' failed.
Cannot find memory tester output file: /builds/user/boost-multi/build/Testing/Temporary/MemoryChecker.51.log

机器非常相似,都是英特尔i7。我能想到的唯一区别是一个是:

**答:**Ubuntu 22.10,Linux 5.19.0-29,Docker 2016年10月20日

另一个:

**B.**Fedora 37,Linux操作系统6.1.7-200.fc37.x86_64,文档扩充程序20.10.23

也许还有一些我不知道的 Docker 的配置。

是否存在可能产生差异的docker配置?或内核配置?或valgrind中的某个选项来解决此问题?

我知道一个事实,在真实的机器(不是docker)valgrind不会产生任何内存错误。
我为valgrind使用的选项总是-leak-check=yes --num-callers=51 --trace-children=yes --leak-check=full --track-origins=yes --gen-suppressions=all。图像中的Valgrind版本是来自debian:testing图像的3.19.0-1
注意这不是valgrind报告的错误,这是valgrind内部的错误,也许唯一的区别是Ubuntu版本的valgrind是在发布模式下编译的,错误被忽略了(〈--这没有意义,valgrind在两种情况下是一样的,因为docker映像是一样的)。
我尝试删除--num-callers=51或将其设置为12(默认值),但无济于事。

imzjd6km

imzjd6km1#

我发现了图像和真实机器之间的差异和一个解决方案。它与文件描述符的数量有关。(这在Mac OS上的valgind bug问题的一个线程中简要指出https://bugs.kde.org/show_bug.cgi?id=381815#c0)
在Ubuntu 22.10中运行的Docker映像内部:

ulimit -n
1048576

在Fedora 37中运行的docker映像内部:

ulimit -n
1073741816

(看起来像一个可笑的数字或溢出)
在Fedora 37 * 和 * Ubuntu 22.10 * 真实 * 计算机中:

ulimit -n
1024

因此,在CI配方中这样做,"解决"了问题:

- ulimit -n       # reports current value
- ulimit -n 1024  # workaround neededed by valgrind in docker running in Fedora 37
- ctest ... (with memcheck)

我不知道为什么这个变通方案有效。
供参考:

$ ulimit --help
...
      -n    the maximum number of open file descriptors
lkaoscv7

lkaoscv72#

首先,用Valgrind参数表示“你做错了”。对于CI,我建议使用两个阶段的方法。在CI运行中使用尽可能多的默认参数(--trace-children=yes可能是必需的,但其他的不是).如果你的代码库有漏洞,那么你可能需要检查漏洞,但如果你能保持零泄漏政策(或仅抑制泄漏),则可以从摘要中判断是否存在新泄漏。在您的CI检测到问题后,您可以使用厨房Flume选项再次运行以获取完整信息。如果不使用所有这些选项,您的运行速度将显著加快。
回到问题上来。
Valgrind试图dup()某个文件(客户机exe,临时文件或类似的文件),它得到的fd比它认为的nofilerlimit要高,所以它Assert。
十亿个文件太荒谬了。
Valgrind将尝试调用prlimit RLIMIT_NOFILE,并回退调用rlimit,然后再回退一次将限制设置为1024。
要真正了解发生了什么,您需要修改Valgrind源代码(m_main. c,setup_file_descriptor,将本地show设置为True)。

fd limits: host, before: cur 65535 max 65535
fd limits: host,  after: cur 65535 max 65535
fd limits: guest       : cur 65523 max 65523

否则我看斯特拉斯

2049  prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=65535, rlim_max=65535}) = 0
2049  prlimit64(0, RLIMIT_NOFILE, {rlim_cur=65535, rlim_max=65535}, NULL) = 0

(all RHEL 7.6修正案64中的上述内容)
编辑:注意上面显示了Valgrind查询和设置资源限制。如果你在运行Valgrind之前使用ulimit来降低限制,那么Valgrind会尝试遵守这个限制。还要注意Valgrind保留了少量(8)文件供自己使用。

相关问题