KEMBAR78
Valgrind tutorial | PDF
VALGRIND TUTORIAL
Satabdi Das
November 2015
Agenda
• What is Valgrind
• Quick Start Guide of Memcheck1.
• Understanding the Output of
Memcheck
• Some Useful Options of Memcheck
2.
• Attaching a debugger
• How Does Valgrind Work?3.
What is Valgrind?
• A Suite of Free and Open Source Debugging
and Profiling tools
• Can detect many memory-related errors
commonly found in C and C++
• Used industry-wide.
• Memcheck
– Most popular of these tools
Quick Start Guide
• Compile your code in debug mode
– Give –g to gcc/g++
– You may also use –o1
• Line numbers in the message may be incorrect
– Do not use –o2 or anything above
• Command to run
• Few finer points
– Memcheck is the default tool. To use other tool, you give
– The --leak-check option turns on the detailed memory leak detector.
valgrind --leak-check=yes prog <args>
valgrind –tool=callgrind prog <args>
Let’s debug some memory error
#include <iostream>
using namespace std;
void func1() {
int* vec = new int [10];
for (int i = 0; i <= 10; ++i) {
vec[i] = 1;
}
}
int main() {
func1();
return 0;
}
==11888== Invalid write of size 4
==11888== at 0x4006F0: func1() (main1.cxx:8)
==11888== by 0x40070F: main (main1.cxx:13)
==11888== Address 0x4c36068 is 0 bytes after a block of size 40 alloc'd
==11888== at 0x4A0674C: operator new[](unsigned long)
(vg_replace_malloc.c:305)
==11888== by 0x4006D5: func1() (main1.cxx:6)
==11888== by 0x40070F: main (main1.cxx:13)
==11888==
==11888==
==11888== HEAP SUMMARY:
==11888== in use at exit: 40 bytes in 1 blocks
==11888== total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==11888==
==11888== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==11888== at 0x4A0674C: operator new[](unsigned long)
(vg_replace_malloc.c:305)
==11888== by 0x4006D5: func1() (main1.cxx:6)
==11888== by 0x40070F: main (main1.cxx:13)
==11888==
==11888== LEAK SUMMARY:
==11888== definitely lost: 40 bytes in 1 blocks
==11888== indirectly lost: 0 bytes in 0 blocks
==11888== possibly lost: 0 bytes in 0 blocks
==11888== still reachable: 0 bytes in 0 blocks
==11888== suppressed: 0 bytes in 0 blocks
==11888==
==11888== For counts of detected and suppressed errors, rerun with: -v
==11888== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)
Understanding the output of
Memcheck
• ==29403== Invalid write of size 4
– Process id : 29403
– Type of error : “Invalid write”
– Below it, the stack trace.
• ==11888== 40 bytes in 1 blocks are definitely
lost in loss record 1 of 1
– Memory leak followed by the stack trace
• Note: Valgrind doesn’t detect static buffer
overflow
int vec2[10];
vec2[10] = 4;
vec2[11] = 5;
Memory Leaks
• What is a memory leak?
– There’s a memory chunk allocated, but you can’t access that
• Memcheck reports following 4 kinds of leaks
1. Still Reachable
• Still have pointer(s) to the start of the block
• No problem. You can still free it. By default not reported
2. Definitely Lost
• No pointer to the memory block could be found
• Can not be freed at the end of the program
3. Indirectly Lost
• All the pointers that point to the block are lost
• For instance if root node of the binary tree is lost, all its children are
indirectly lost
4. Possibly Lost
• There’s a chain of one or more pointers, but one of the pointers is an interior
pointers
Memory Error
• Different types of errors
– Illegal read / Illegal write error
• This happens when your program reads or writes
memory at a place which Memcheck reckons it
shouldn't
void func1() {
int* vec = new int [11];
for (int i = 0; i <= 10; ++i) {
vec[i] = 1;
}
delete vec;
vec[10] = 4;
}
Memory Error (Contd.)
• Different types of errors
– Use of Uninitialized values
• when your program uses a value which hasn't been initialised --
in other words, is undefined
• Sources of uninitialized value
– Local variables in procedures which have not been initialised
– The contents of heap blocks before you write something
there
void func1() {
int* vec = new int [11];
if (vec[0] == 4) {
cout << "Initialized" << endl;
} else {
cout << "Not initialized" << endl;
}
}
Memory Error (Contd.)
• Different types of errors
– Use of uninitialized values in system calls
int main( void ) {
char* arr = malloc(10);
int* arr2 = malloc(sizeof(int));
write( 1 /* stdout */, arr, 10 );
exit(arr2[0]);
}
1. Syscall param write(buf) points to uninitialised byte(s)
2. Syscall param exit(error_code) contains uninitialised byte(s)
Memory Error (Contd.)
• Different types of errors
– Illegal Free
• Program freeing memory block twice
– Heap block freed with inappropriate deallocation
function
• If allocated with malloc, calloc, realloc, valloc or memalign,
you must deallocate with free.
• If allocated with new, you must deallocate with delete.
• If allocated with new[], you must deallocate with delete[].
– Overlapping source and destination
• Probable places – memcpy, strcpy etc.
Some useful options of Memcheck
– Maximum number of entries shown in the stack trace
– If you use –log-file=<file name>.%p, then the process ID will be added. For
instance
– Needed if your program creates sub-processes through exec system call.
• valgrind –h will list you many other basic user options
--num-callers=<number> [default : 12]
--log-file=<file name>
$ valgrind --log-file=valgrind.log.%p ./main1
$ ls
$ main1 main1.cxx valgrind.log.2866
--trace-children=<yes|no> [default: no]
Some useful options of Memcheck
• A very common message seen is – "Conditional jump or move
depends on uninitialised value(s)“
– Memcheck reports use of uninitialised values.
– To know sources of uninitialised data, use the following option
• Suppressing errors
– You may need it to suppress errors in library code.
– Valgrind will pause after every error and ask you to print the
suppression. Press Y.
– Copy all the messages into a file (e.g. my.supp) and in the future
valgrind run, use
--track-origin=yes [default : no]
--gen-suppressions=yes
valgrind --leak-check=yes --suppressions=./my.supp ./main1
Suppressing errors
==14682== Conditional jump or move depends on uninitialised value(s)
==14682== at 0x400873: func1() (main1.cxx:7)
==14682== by 0x4008B9: main (main1.cxx:15)
==14682==
==14682==
==14682== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ---- y
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:_Z5func1v
fun:main
}
Not initialized
==14682==
Passing options to Valgrind
• Valgrind read options from following 3 places
– ~/.valgrindrc
– $VALGRIND_OPTS
– ./.valgrindrc
Memcheck - overview
• Detects the following errors
– Accessing memory you shouldn’t
• But it can’t detect memory errors on statically allocated memory.
– Using undefined values
– Incorrect freeing of heap memory
– Memory leaks etc.
• Usually, your program should have no error.
• GUI for Valgrind
– Valkyrie
– Alleyoop
– MemcheckView
Attaching a debugger
• 3 simple steps
valgrind --vgdb-error=0 ./main1 [In one terminal]
==17332== Memcheck, a memory error detector
==17332== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==17332== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17332== Command: ./main1
==17332==
==17332== (action at startup) vgdb me ...
==17332==
==17332== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==17332== /path/to/gdb ./main1
==17332== and then give GDB the following command
==17332== target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=17332
==17332== --pid is optional if only one valgrind process is running
==17332==
gdb ./main1 [In another terminal]
(gdb) target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=17332
Attaching a debugger(contd.)
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000000000400730 in func1 () at main1.cxx:8
8 vec[i] = 1;
(gdb)
Attaching a debugger(contd.)
• Monitor Commands
– Gdb can send commands to the gdbserver
– The Valgrind gdbserver provides extra valgrind-specific functionality
through these commands
– GDB will send the leak_check command to the Valgrind gdbserver.
– The Valgrind gdbserver will execute the monitor command itself, if it
recognises it to be a Valgrind core monitor command.
– If it is not recognised as such, it is assumed to be tool-specific and is
handed to the tool for execution.
(gdb) monitor leak_check full reachable any
Attaching a debugger(contd.)
• Why do we need all these steps
– Gdb is typically used to debug processes running on the same
machine
– For Remote Debugging, gdbserver is implemented
– A process runs on Valgrind’s synthetic CPU
– Valgrind provides a gdbserver implementation
– Valgrind gdbserver can be activated using 3 commands. One of
them is –vgdb-error=0.
• It tells the gdbserver to become active once the specified number of
errors occurred
– Communication between the GDB and the Valgrind GDB server
happens through a pipe and vgdb
• target remote | vgdb => tells the GDB to debug a remote target
How does Valgrind(Memcheck) Work?
• Memcheck adds instrumentation code to the executable
• Valgrind core coordinates the execution of the
instrumented code
• V-Bits
– Every bit of data in your program is associated with a “Valid
Value Bit” or V-Bit
– Establishes validity of value
– Copying values around does not cause Memcheck to check for,
or report on, errors.
– However, when a value is used in a way which might
conceivably affect your program's externally-visible behaviour,
the associated V bits are immediately checked.
How does Valgrind(Memcheck) Work?
• A-Bits
– To check if the data at that location should be
accessed or not
– Before every read/write Memcheck checks A-Bits
– Each byte has a single A-bit
List of Other Valgrind Tools
• Cachegrind
– Cache profiler. Pinpoint source of cache-miss
• Callgrind
– Provides call graph along with above output
• Helgrind
– Thread debugger. Finds data races etc
• Drd
– Detects errors in multithread C/C++ programs
• Massif
– Heap profiler – heap usage etc
- etc
Reference
• http://valgrind.org/docs/manual/index.html

Valgrind tutorial

  • 1.
  • 2.
    Agenda • What isValgrind • Quick Start Guide of Memcheck1. • Understanding the Output of Memcheck • Some Useful Options of Memcheck 2. • Attaching a debugger • How Does Valgrind Work?3.
  • 3.
    What is Valgrind? •A Suite of Free and Open Source Debugging and Profiling tools • Can detect many memory-related errors commonly found in C and C++ • Used industry-wide. • Memcheck – Most popular of these tools
  • 4.
    Quick Start Guide •Compile your code in debug mode – Give –g to gcc/g++ – You may also use –o1 • Line numbers in the message may be incorrect – Do not use –o2 or anything above • Command to run • Few finer points – Memcheck is the default tool. To use other tool, you give – The --leak-check option turns on the detailed memory leak detector. valgrind --leak-check=yes prog <args> valgrind –tool=callgrind prog <args>
  • 5.
    Let’s debug somememory error #include <iostream> using namespace std; void func1() { int* vec = new int [10]; for (int i = 0; i <= 10; ++i) { vec[i] = 1; } } int main() { func1(); return 0; } ==11888== Invalid write of size 4 ==11888== at 0x4006F0: func1() (main1.cxx:8) ==11888== by 0x40070F: main (main1.cxx:13) ==11888== Address 0x4c36068 is 0 bytes after a block of size 40 alloc'd ==11888== at 0x4A0674C: operator new[](unsigned long) (vg_replace_malloc.c:305) ==11888== by 0x4006D5: func1() (main1.cxx:6) ==11888== by 0x40070F: main (main1.cxx:13) ==11888== ==11888== ==11888== HEAP SUMMARY: ==11888== in use at exit: 40 bytes in 1 blocks ==11888== total heap usage: 1 allocs, 0 frees, 40 bytes allocated ==11888== ==11888== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==11888== at 0x4A0674C: operator new[](unsigned long) (vg_replace_malloc.c:305) ==11888== by 0x4006D5: func1() (main1.cxx:6) ==11888== by 0x40070F: main (main1.cxx:13) ==11888== ==11888== LEAK SUMMARY: ==11888== definitely lost: 40 bytes in 1 blocks ==11888== indirectly lost: 0 bytes in 0 blocks ==11888== possibly lost: 0 bytes in 0 blocks ==11888== still reachable: 0 bytes in 0 blocks ==11888== suppressed: 0 bytes in 0 blocks ==11888== ==11888== For counts of detected and suppressed errors, rerun with: -v ==11888== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)
  • 6.
    Understanding the outputof Memcheck • ==29403== Invalid write of size 4 – Process id : 29403 – Type of error : “Invalid write” – Below it, the stack trace. • ==11888== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1 – Memory leak followed by the stack trace • Note: Valgrind doesn’t detect static buffer overflow int vec2[10]; vec2[10] = 4; vec2[11] = 5;
  • 7.
    Memory Leaks • Whatis a memory leak? – There’s a memory chunk allocated, but you can’t access that • Memcheck reports following 4 kinds of leaks 1. Still Reachable • Still have pointer(s) to the start of the block • No problem. You can still free it. By default not reported 2. Definitely Lost • No pointer to the memory block could be found • Can not be freed at the end of the program 3. Indirectly Lost • All the pointers that point to the block are lost • For instance if root node of the binary tree is lost, all its children are indirectly lost 4. Possibly Lost • There’s a chain of one or more pointers, but one of the pointers is an interior pointers
  • 8.
    Memory Error • Differenttypes of errors – Illegal read / Illegal write error • This happens when your program reads or writes memory at a place which Memcheck reckons it shouldn't void func1() { int* vec = new int [11]; for (int i = 0; i <= 10; ++i) { vec[i] = 1; } delete vec; vec[10] = 4; }
  • 9.
    Memory Error (Contd.) •Different types of errors – Use of Uninitialized values • when your program uses a value which hasn't been initialised -- in other words, is undefined • Sources of uninitialized value – Local variables in procedures which have not been initialised – The contents of heap blocks before you write something there void func1() { int* vec = new int [11]; if (vec[0] == 4) { cout << "Initialized" << endl; } else { cout << "Not initialized" << endl; } }
  • 10.
    Memory Error (Contd.) •Different types of errors – Use of uninitialized values in system calls int main( void ) { char* arr = malloc(10); int* arr2 = malloc(sizeof(int)); write( 1 /* stdout */, arr, 10 ); exit(arr2[0]); } 1. Syscall param write(buf) points to uninitialised byte(s) 2. Syscall param exit(error_code) contains uninitialised byte(s)
  • 11.
    Memory Error (Contd.) •Different types of errors – Illegal Free • Program freeing memory block twice – Heap block freed with inappropriate deallocation function • If allocated with malloc, calloc, realloc, valloc or memalign, you must deallocate with free. • If allocated with new, you must deallocate with delete. • If allocated with new[], you must deallocate with delete[]. – Overlapping source and destination • Probable places – memcpy, strcpy etc.
  • 12.
    Some useful optionsof Memcheck – Maximum number of entries shown in the stack trace – If you use –log-file=<file name>.%p, then the process ID will be added. For instance – Needed if your program creates sub-processes through exec system call. • valgrind –h will list you many other basic user options --num-callers=<number> [default : 12] --log-file=<file name> $ valgrind --log-file=valgrind.log.%p ./main1 $ ls $ main1 main1.cxx valgrind.log.2866 --trace-children=<yes|no> [default: no]
  • 13.
    Some useful optionsof Memcheck • A very common message seen is – "Conditional jump or move depends on uninitialised value(s)“ – Memcheck reports use of uninitialised values. – To know sources of uninitialised data, use the following option • Suppressing errors – You may need it to suppress errors in library code. – Valgrind will pause after every error and ask you to print the suppression. Press Y. – Copy all the messages into a file (e.g. my.supp) and in the future valgrind run, use --track-origin=yes [default : no] --gen-suppressions=yes valgrind --leak-check=yes --suppressions=./my.supp ./main1
  • 14.
    Suppressing errors ==14682== Conditionaljump or move depends on uninitialised value(s) ==14682== at 0x400873: func1() (main1.cxx:7) ==14682== by 0x4008B9: main (main1.cxx:15) ==14682== ==14682== ==14682== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ---- y { <insert_a_suppression_name_here> Memcheck:Cond fun:_Z5func1v fun:main } Not initialized ==14682==
  • 15.
    Passing options toValgrind • Valgrind read options from following 3 places – ~/.valgrindrc – $VALGRIND_OPTS – ./.valgrindrc
  • 16.
    Memcheck - overview •Detects the following errors – Accessing memory you shouldn’t • But it can’t detect memory errors on statically allocated memory. – Using undefined values – Incorrect freeing of heap memory – Memory leaks etc. • Usually, your program should have no error. • GUI for Valgrind – Valkyrie – Alleyoop – MemcheckView
  • 17.
    Attaching a debugger •3 simple steps valgrind --vgdb-error=0 ./main1 [In one terminal] ==17332== Memcheck, a memory error detector ==17332== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==17332== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==17332== Command: ./main1 ==17332== ==17332== (action at startup) vgdb me ... ==17332== ==17332== TO DEBUG THIS PROCESS USING GDB: start GDB like this ==17332== /path/to/gdb ./main1 ==17332== and then give GDB the following command ==17332== target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=17332 ==17332== --pid is optional if only one valgrind process is running ==17332== gdb ./main1 [In another terminal] (gdb) target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=17332
  • 18.
    Attaching a debugger(contd.) (gdb)c Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0x0000000000400730 in func1 () at main1.cxx:8 8 vec[i] = 1; (gdb)
  • 19.
    Attaching a debugger(contd.) •Monitor Commands – Gdb can send commands to the gdbserver – The Valgrind gdbserver provides extra valgrind-specific functionality through these commands – GDB will send the leak_check command to the Valgrind gdbserver. – The Valgrind gdbserver will execute the monitor command itself, if it recognises it to be a Valgrind core monitor command. – If it is not recognised as such, it is assumed to be tool-specific and is handed to the tool for execution. (gdb) monitor leak_check full reachable any
  • 20.
    Attaching a debugger(contd.) •Why do we need all these steps – Gdb is typically used to debug processes running on the same machine – For Remote Debugging, gdbserver is implemented – A process runs on Valgrind’s synthetic CPU – Valgrind provides a gdbserver implementation – Valgrind gdbserver can be activated using 3 commands. One of them is –vgdb-error=0. • It tells the gdbserver to become active once the specified number of errors occurred – Communication between the GDB and the Valgrind GDB server happens through a pipe and vgdb • target remote | vgdb => tells the GDB to debug a remote target
  • 21.
    How does Valgrind(Memcheck)Work? • Memcheck adds instrumentation code to the executable • Valgrind core coordinates the execution of the instrumented code • V-Bits – Every bit of data in your program is associated with a “Valid Value Bit” or V-Bit – Establishes validity of value – Copying values around does not cause Memcheck to check for, or report on, errors. – However, when a value is used in a way which might conceivably affect your program's externally-visible behaviour, the associated V bits are immediately checked.
  • 22.
    How does Valgrind(Memcheck)Work? • A-Bits – To check if the data at that location should be accessed or not – Before every read/write Memcheck checks A-Bits – Each byte has a single A-bit
  • 23.
    List of OtherValgrind Tools • Cachegrind – Cache profiler. Pinpoint source of cache-miss • Callgrind – Provides call graph along with above output • Helgrind – Thread debugger. Finds data races etc • Drd – Detects errors in multithread C/C++ programs • Massif – Heap profiler – heap usage etc - etc
  • 24.