valgrind Command
Debug memory errors and profile applications
Syntax:
valgrind [OPTIONS] program [program-options]
Note: Valgrind is a powerful debugging and profiling tool suite that helps detect memory management bugs, memory leaks, and performance issues in programs. It works by running programs on a synthetic CPU.
Description
Valgrind is an instrumentation framework for building dynamic analysis tools. It includes several tools for debugging and profiling programs, with Memcheck being the most popular tool for detecting memory errors. Valgrind can detect memory leaks, buffer overflows, use of uninitialized memory, and other memory-related bugs.
Performance Impact: Programs run under Valgrind execute 10-50 times slower than normal, so it's primarily used during development and testing phases.
Valgrind Tools
| Tool | Purpose |
|---|---|
memcheck |
Memory error detector (default tool) |
cachegrind |
Cache and branch-prediction profiler |
callgrind |
Call-graph generating cache profiler |
helgrind |
Thread error detector |
drd |
Thread error detector (alternative to helgrind) |
massif |
Heap profiler |
lackey |
Example tool for instruction counting |
Common Options
| Option | Description |
|---|---|
--tool=toolname |
Select which tool to use (default: memcheck) |
--leak-check=yes|no|full |
Enable detailed memory leak detection |
--show-leak-kinds=all |
Show all types of memory leaks |
--track-origins=yes |
Track origins of uninitialized values |
--verbose |
Increase verbosity level |
--log-file=filename |
Write output to specified file |
--suppressions=file |
Use suppression file to ignore known issues |
--gen-suppressions=yes |
Generate suppression entries |
--num-callers=number |
Show number of stack frames in error messages |
Examples
Basic memory checking:
valgrind ./myprogram # Runs myprogram with default memcheck tool valgrind --leak-check=full ./myprogram # Detailed memory leak detection
Comprehensive memory analysis:
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes ./myprogram # Output saved to file valgrind --leak-check=full --log-file=valgrind.log ./myprogram
Sample C program with memory errors:
// test.c - Program with intentional memory errors
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = malloc(10 * sizeof(int));
// Memory leak - forgot to free
ptr[0] = 42;
// Use after free
free(ptr);
printf("Value: %d\n", ptr[0]); // Error!
return 0;
}
# Compile and run with valgrind
gcc -g -o test test.c
valgrind --leak-check=full ./test
Thread error detection:
# Check for race conditions and thread errors valgrind --tool=helgrind ./threaded_program # Alternative thread checker valgrind --tool=drd ./threaded_program
Cache profiling:
# Profile cache usage valgrind --tool=cachegrind ./myprogram # Generate call graph valgrind --tool=callgrind ./myprogram # View callgrind output kcachegrind callgrind.out.12345
Heap profiling:
# Profile heap usage over time valgrind --tool=massif ./myprogram # View massif output ms_print massif.out.12345
Understanding Valgrind Output
Sample memory error output:
==12345== Invalid read of size 4 ==12345== at 0x40051B: main (test.c:11) ==12345== Address 0x4c27040 is 0 bytes inside a block of size 40 free'd ==12345== at 0x4A0736C: free (vg_replace_malloc.c:446) ==12345== at 0x400514: main (test.c:10) ==12345== HEAP SUMMARY: ==12345== in use at exit: 0 bytes in 0 blocks ==12345== total heap usage: 1 allocs, 1 frees, 40 bytes allocated ==12345== ==12345== LEAK SUMMARY: ==12345== definitely lost: 0 bytes in 0 blocks ==12345== indirectly lost: 0 bytes in 0 blocks ==12345== possibly lost: 0 bytes in 0 blocks ==12345== still reachable: 0 bytes in 0 blocks ==12345== suppressed: 0 bytes in 0 blocks
Memory Leak Types
| Leak Type | Description |
|---|---|
definitely lost |
Memory that is leaked and no longer accessible |
indirectly lost |
Memory lost due to definitely lost blocks |
possibly lost |
Memory that might be leaked (interior pointers) |
still reachable |
Memory still accessible but not freed at exit |
suppressed |
Leaks ignored due to suppression rules |
Advanced Usage
Custom suppression file:
# Create suppression file (my_suppressions.supp)
{
ignore_glibc_leak
Memcheck:Leak
fun:malloc
fun:_dl_*
}
# Use suppression file
valgrind --suppressions=my_suppressions.supp ./myprogram
# Generate suppressions automatically
valgrind --gen-suppressions=yes ./myprogram
Debugging with GDB integration:
# Run valgrind with GDB server valgrind --vgdb=yes --vgdb-error=0 ./myprogram # In another terminal, connect GDB gdb ./myprogram (gdb) target remote | vgdb
Automated testing script:
#!/bin/bash
# Script to run valgrind tests
PROGRAM="./myprogram"
LOG_DIR="valgrind_logs"
mkdir -p "$LOG_DIR"
echo "Running memory check..."
valgrind --tool=memcheck \
--leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
--log-file="$LOG_DIR/memcheck.log" \
"$PROGRAM"
echo "Running thread check..."
valgrind --tool=helgrind \
--log-file="$LOG_DIR/helgrind.log" \
"$PROGRAM"
echo "Running cache profiling..."
valgrind --tool=cachegrind \
--cachegrind-out-file="$LOG_DIR/cachegrind.out" \
"$PROGRAM"
echo "Valgrind analysis complete. Check $LOG_DIR for results."
Compilation Tips
Optimal compilation flags:
# For best valgrind results gcc -g -O0 -fno-inline -o myprogram myprogram.c # Explanation: # -g: Include debugging information # -O0: No optimization (easier to debug) # -fno-inline: Prevent function inlining
Performance Considerations
Reducing valgrind overhead:
# Minimal checking for faster execution valgrind --tool=memcheck --leak-check=no ./myprogram # Reduce stack trace depth valgrind --num-callers=4 ./myprogram # Focus on specific errors valgrind --track-origins=no --leak-check=summary ./myprogram
Integration with Build Systems
Makefile integration:
# Makefile PROGRAM = myprogram SOURCES = main.c utils.c $(PROGRAM): $(SOURCES) gcc -g -O0 -o $(PROGRAM) $(SOURCES) valgrind: $(PROGRAM) valgrind --leak-check=full --log-file=valgrind.log ./$(PROGRAM) valgrind-full: $(PROGRAM) valgrind --tool=memcheck \ --leak-check=full \ --show-leak-kinds=all \ --track-origins=yes \ --log-file=valgrind-full.log \ ./$(PROGRAM) .PHONY: valgrind valgrind-full
Common Use Cases
- Memory leak detection: Finding unreleased memory allocations
- Buffer overflow detection: Catching array bounds violations
- Use-after-free detection: Finding access to freed memory
- Uninitialized memory detection: Catching use of uninitialized variables
- Thread synchronization: Detecting race conditions and deadlocks
- Performance profiling: Analyzing cache usage and call patterns
- Heap analysis: Understanding memory usage patterns
- Code quality assurance: Automated testing for memory safety
Best Practices
- Compile with debug symbols (-g) and no optimization (-O0)
- Use --leak-check=full for comprehensive leak detection
- Enable --track-origins=yes to find sources of uninitialized data
- Create suppression files for known false positives
- Run valgrind regularly during development, not just before release
- Use different tools for different types of analysis
- Save valgrind output to files for later analysis
- Integrate valgrind checks into your build/test process
- Fix memory errors in order of severity
- Test with realistic data sets and usage patterns
Limitations
- Significant performance overhead (10-50x slower)
- May not detect all types of memory errors
- False positives can occur, especially with optimized code
- Limited support for some system calls and libraries
- Memory usage increases significantly
- Some threading issues may not be reproducible under valgrind