14

有没有办法在运行时识别从 valgrind 中运行的可执行文件?我有一组 C++ 单元测试,其中一个预计std::vector::reserve会抛出std::bad_alloc. 当我在 valgrind 下运行它时,它完全退出,阻止我测试内存泄漏(使用 valgrind)和行为(期望抛出异常)。

这是一个重现它的最小示例:

#include <vector>
int main()
{
    size_t uint_max = static_cast<size_t>(-1);
    std::vector<char> v;
    v.reserve(uint_max);
}

运行 valgrind,我得到以下输出:

Warning: silly arg (-1) to __builtin_new()
new/new[] failed and should throw an exception, but Valgrind
   cannot throw exceptions and so is aborting instead.  Sorry.
   at 0x40192BC: VALGRIND_PRINTF_BACKTRACE (valgrind.h:319)
   by 0x401C823: operator new(unsigned) (vg_replace_malloc.c:164)
   by 0x80487BF: std::vector<char, std::allocator<char> >::reserve(unsigned) new_allocator.h:92)
   by 0x804874D: main (vg.cxx:6)

我想修改我的单元测试,以便在从 valgrind 中运行时跳过有问题的代码。这可能吗?

4

3 回答 3

25

您应该从 Valgrind 手册中查看此页面RUNNING_ON_VALGRIND,它包含一个宏(包含在 valgrind.h 中),它可以满足您的需求。

于 2008-12-13T21:48:22.467 回答
7

如果不想包含valgrind.h(需要 autoconf 测试或类似的)或使用包装器,这里有一个针对 Linux(和其他使用 ELF 的系统?)的启发式方法:测试LD_PRELOAD环境变量的值,因为 Valgrind 通过预加载库工作。我在 C 中使用以下测试来检查是否LD_PRELOAD包含字符串"/valgrind/""/vgpreload"

int tests_run_within_valgrind (void)
{
  char *p = getenv ("LD_PRELOAD");
  if (p == NULL)
    return 0;
  return (strstr (p, "/valgrind/") != NULL ||
          strstr (p, "/vgpreload") != NULL);
}

其他系统可能有类似的解决方案。我建议使用以下命令来查看环境是否提到了 Valgrind:

valgrind env | grep -i valgrind

编辑:如果您尝试在 macOS 或在 amd64 内核上运行的 FreeBSD i386 上执行此操作相对不太可能发生,那么环境变量会有所不同。

  • macOS 使用 DYLD_INSERT_LIBRARIES
  • FreeBSD 使用 LD_32_PRELOAD(仅适用于 amd64 上的 i386,不适用于 amd64 上的 amd64 或 i386 上的 i386)。

普通 LD_PRELOAD 应该适用于所有 Linux 和 Solaris 变体。

于 2020-06-13T19:32:26.213 回答
1

我查看了 valgrind 文档并没有找到简单的答案。但是您可以尝试以下几件事:

  • 围绕有问题的新操作编写自己的包装器,并在 valgrind 获取其私有新功能之前引发异常。

  • 尝试上面建议的海报,除了使用环境变量而不是命令行选项(需要管道):

    MYAPP_UNIT_TESTS_DISABLED="NEW_MINUS_ONE,FLY_TO_MOON,DEREF_NULL" valgrind myapp
    

然后你可以很容易地写一个函数

bool unit_test_enabled(const char *testname);

根据 getenv(3) 返回的值保护您的单元测试。

于 2008-12-13T19:54:42.447 回答