valgrind - hellgrind 与泄漏检查的不同结果

valgrind - different results with hellgrind vs leak-check

我有一些我不明白的奇怪行为。代码有点复杂,所以我不会在这里发布它,而是描述行为,希望知道 valgrind 工作原理的人有一个想法,尽管信息很少,但我可以追求 .

背景:

我正在为基于 c/c++ 的开源代理建模平台开发一些附加功能 fork @ my github。编译没问题。根据我对测试程序的验证,到目前为止一切似乎都正常工作。此外,valgrind 不会报告任何相关错误。但是,可再现性(至关重要)很奇怪。

在框架内定义了一个模型文件(基本上是模拟的初始化运行)。基于此文件,应该能够重现完全相同的输出(并且与平台无关)。在某种程度上这是有效的:如果我启动模拟环境(GUI 版本),加载文件并 运行 它,它每次都会产生相同的结果。另外,使用命令行版本,我每次都得到相同的结果。

但是,如果在模拟环境的一个 运行ning 实例中,我 运行 同一个模型不止一次,那么就会出现奇怪的行为 - 有时......

使用的编译器选项:

CC=g++
GLOBAL_CC=-march=native -std=gnu++14
SSWITCH_CC=-fnon-call-exceptions -Og -ggdb3 -Wall

设置:

我运行编译文件,内部给程序编译,固定模拟设置三遍。现在,它每次都应该产生完全相同的结果,我通过在不同阶段打印随机数来检查。

奇怪的行为:

选项#1:

当我运行程序在valgrind中使用选项时:

valgrind --leak-check=full --leak-resolution=high --show-reachable=yes

我在内部没有得到相同的结果

选项 1 的报告:

Finished processing sim1
==6206==
==6206== HEAP SUMMARY:
==6206==     in use at exit: 43 bytes in 1 blocks
==6206==   total heap usage: 4,124,309 allocs, 4,124,308 frees, 888,390,511 bytes allocated
==6206==
==6206== 43 bytes in 1 blocks are still reachable in loss record 1 of 1
==6206==    at 0x4C2DDCF: realloc (vg_replace_malloc.c:785)
==6206==    by 0x5BE7FB2: getcwd (getcwd.c:84)
==6206==    by 0x143391: lsdmain(int, char**) (lsdmain.cpp:203)
==6206==    by 0x10C37D: main (main_gnuwin.cpp:29)
==6206==
==6206== LEAK SUMMARY:
==6206==    definitely lost: 0 bytes in 0 blocks
==6206==    indirectly lost: 0 bytes in 0 blocks
==6206==      possibly lost: 0 bytes in 0 blocks
==6206==    still reachable: 43 bytes in 1 blocks
==6206==         suppressed: 0 bytes in 0 blocks
==6206==
==6206== For counts of detected and suppressed errors, rerun with: -v
==6206== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

选项#2

但是,当我改用以下选项时:

valgrind --tool=helgrind

我每次使用命令行版本都会得到相同的结果。有趣的是,选项 #1 的第一个结果与选项 #2 的结果相同。

我很乐意提出任何建议。而且,我不是受过训练的计算机科学家......我正在使用 mt1937(每次都重新初始化) - 但模拟之间的初始随机数是相同的,所以我认为错误不在这里。尽管稍后在 运行 选项 #1 中随机数发生变化(这是我的测试,除了模拟需要找到平衡的时间)。

最后,我找到了问题所在:在程序的两个点上,我对一个临时向量进行排序,其中包含一对距离值和位于 2d space:

上的对象指针

std::sort( vector.begin(),vector.end() ); // vector of std::pairs<double, pointer>

显然,解决方案是仅按对中的第一项排序:

std::sort( vector.begin(),vector.end(), [](auto const &A, auto const &B ){return A.first < B.first; } );

关于为什么我没有直接发现这个问题的一些评论:

  • 当我实现这种排序时,我打算实现它 "stable"。对象的指针是独一无二的,因此在不同的子集中,顺序是相同的,并且与我如何将项目添加到集合中无关。
  • 我不认为指针值是(不准确,但实际上)运行我无法控制的 dom 数字。
  • 我没看到这个,因为不知何故 OS(或其他)总是在程序的不同调用之间分配相同的指针值(我建议有一个 "virtual" space 总是再次初始化)。因此,我没有暗示指针是问题所在。
  • 奇怪的是,当我 运行 使用 Valgrind 和 --tool=helgrind 选项的程序时,问题并没有持续存在。我得到的一个建议(离线)是 memcheck 使用给定模式预初始化内存,如果未初始化的变量是原因,这将是一个答案。看起来,helgrind 还控制了不同范围内的内存,为我随后的每个模拟提供了一个 "fresh" 虚拟内存,这样我的指针排序在重复循环中是稳定的。

我希望这对遇到同样问题的人有所帮助。感谢所有的建议!