Valgrind is a framework for building tools that analyze programs as they run, and the platform behind a family of widely used dynamic analysis tools. Rather than requiring a program to be recompiled or relinked, Valgrind takes an ordinary executable and runs it on a software-simulated CPU, instrumenting the program’s machine code on the fly. This technique, dynamic binary instrumentation, lets Valgrind observe and check every memory access and every value the program computes.
The framework’s design is set out in the paper Valgrind: A Framework for Heavyweight Dynamic Binary Instrumentation by Nicholas Nethercote and Julian Seward, presented at the ACM SIGPLAN PLDI conference in 2007. The paper describes Valgrind as a dynamic binary instrumentation framework for building heavyweight dynamic binary analysis tools, and gives particular attention to its support for shadow values, where every register and memory location used by the program is shadowed by a second value that the analysis tool maintains. Shadow values are the powerful but difficult-to-implement technique that makes Valgrind’s deepest checks possible. The work later received PLDI’s Most Influential Paper award for that year.
By far the most heavily used Valgrind tool is Memcheck. Its manual states plainly that Memcheck is a memory error detector for C and C++ programs, and enumerates the problems it finds: reads and writes outside allocated blocks and beyond the stack, use of memory after it has been freed, use of uninitialized values in ways that affect program behavior, double frees and mismatched allocation and deallocation functions, and memory leaks where allocated blocks are no longer reachable. Memcheck achieves this by tracking, for every byte and bit the program touches, whether the corresponding address is addressable and whether its value has been defined, using what the manual calls A-bits and V-bits.
The cost of this thoroughness is speed. Running under Memcheck can slow a program by an order of magnitude or more, which is why the 2007 paper calls these heavyweight tools. The trade-off is that the bugs Memcheck catches, especially uninitialized-value errors and subtle out-of-bounds accesses, are exactly the ones that produce intermittent crashes and security vulnerabilities and that are hardest to find by inspection or with a conventional debugger. The leak check, controlled by options such as —leak-check, reports at program exit which allocations were never freed and where they were allocated.
Beyond Memcheck, the Valgrind distribution includes tools such as Cachegrind and Callgrind for cache and call-graph profiling, Helgrind and DRD for detecting threading errors, and Massif for heap profiling, all built on the same instrumentation core. By making heavyweight memory checking practical on real, unmodified binaries, Valgrind became a standard part of the C and C++ development and continuous-integration toolbox and a major practical contributor to memory safety in widely deployed software.