【问题标题】:How can I detect if a program is running from within valgrind?如何检测程序是否从 valgrind 中运行?
【发布时间】:2010-09-26 19:10:44
【问题描述】:

有没有办法在运行时识别从 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 中运行时跳过有问题的代码。这可能吗?

【问题讨论】:

    标签: c++ unit-testing valgrind


    【解决方案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) 返回的值保护您的单元测试。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 感谢您,我已经使用 *grind 多年,但几乎没有接触过界面。如果 valgrind/valgrind.h 存在,在 valrgind 下运行时,它会自动打开我的调试 printfs() 和断言:) 在 autoconf 中包含该宏很容易使理智:) 再次感谢!很有帮助
      【解决方案3】:

      如果不想包含 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 变体。

      【讨论】:

        猜你喜欢
        • 2012-08-18
        • 2018-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-15
        相关资源
        最近更新 更多