Top Banner
V ALGRIND TUTORIAL Satabdi Das November 2015
24

Valgrind tutorial

Jan 29, 2018

Download

Software

Satabdi Das
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Valgrind tutorial

VALGRIND TUTORIAL

Satabdi Das

November 2015

Page 2: Valgrind tutorial

Agenda

• What is Valgrind

• Quick Start Guide of Memcheck 1. • Understanding the Output of

Memcheck

• Some Useful Options of Memcheck 2.

• Attaching a debugger

• How Does Valgrind Work? 3.

Page 3: Valgrind tutorial

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

Page 4: Valgrind tutorial

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>

Page 5: Valgrind tutorial

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)

Page 6: Valgrind tutorial

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;

Page 7: Valgrind tutorial

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

Page 8: Valgrind tutorial

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; }

Page 9: Valgrind tutorial

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; } }

Page 10: Valgrind tutorial

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)

Page 11: Valgrind tutorial

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.

Page 12: Valgrind tutorial

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]

Page 13: Valgrind tutorial

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

Page 14: Valgrind tutorial

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==

Page 15: Valgrind tutorial

Passing options to Valgrind

• Valgrind read options from following 3 places

– ~/.valgrindrc

– $VALGRIND_OPTS

– ./.valgrindrc

Page 16: Valgrind tutorial

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

Page 17: Valgrind tutorial

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

Page 18: Valgrind tutorial

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)

Page 19: Valgrind tutorial

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

Page 20: Valgrind tutorial

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

Page 21: Valgrind tutorial

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.

Page 22: Valgrind tutorial

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

Page 23: Valgrind tutorial

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

Page 24: Valgrind tutorial

Reference

• http://valgrind.org/docs/manual/index.html