Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect if a program is running from within valgrind?

Is there a way to identify at run-time of an executable is being run from within valgrind? I have a set of C++ unit tests, and one of them expects std::vector::reserve to throw std::bad_alloc. When I run this under valgrind, it bails out completely, preventing me from testing for both memory leaks (using valgrind) and behavior (expecting the exception to be thrown).

Here's a minimal example that reproduces it:

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

Running valgrind, I get this output:

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)

I'd like to modify my unit test to simply skip the offending code when it's being run from within valgrind. Is this possible?

like image 972
Tom Avatar asked Dec 13 '08 17:12

Tom


2 Answers

You should look at this page from the Valgrind manual, it contains a RUNNING_ON_VALGRIND macro (included from valgrind.h) which does what you want.

like image 125
Hasturkun Avatar answered Sep 22 '22 01:09

Hasturkun


If one does not want to include valgrind.h (which requires an autoconf test or similar) or use a wrapper, here's a heuristic for Linux (and other systems using ELF?): test the value of the LD_PRELOAD environment variable since Valgrind works by preloading libraries. I use the following test in C to check whether LD_PRELOAD contains the string "/valgrind/" or "/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);
}

Other systems might have a similar solution. I suggest the following command to see whether the environment mentions Valgrind:

valgrind env | grep -i valgrind

Edit: In the relatively unlikely event that you are trying to do this either on macOS or on FreeBSD i386 running on an amd64 kernel then the environment variables are different.

  • macOS uses DYLD_INSERT_LIBRARIES
  • FreeBSD uses LD_32_PRELOAD (ONLY for i386 on amd64, not amd64 on amd64 or i386 on i386).

Plain LD_PRELOAD should work for all Linux and Solaris variants.

like image 38
vinc17 Avatar answered Sep 20 '22 01:09

vinc17