14
Tutorial: Valgrind CS447/CS647/ECE453/ECE653/SE465 Lei Zhang [email protected] 2014-2-14

T3-Valgrind

Embed Size (px)

Citation preview

Page 1: T3-Valgrind

Tutorial: ValgrindCS447/CS647/ECE453/ECE653/SE465

Lei [email protected]

2014-2-14

Page 2: T3-Valgrind

What is Valgrind

Valgrind is a GPL'd system for debugging and profiling Linux programs. With Valgrind's tool suite you can automatically detect many memory management and threading bugs, avoiding hours of frustrating bug-hunting, making your programs more stable. You can also perform detailed profiling to help speed up your programs.

-- http://valgrind.org/info/

Page 3: T3-Valgrind

Valgrind Tool Suite

An instrumentation framework for building dynamic analysis tools● Memcheck: memory error detector● Cachegrind: cache profiler● Helgrind, DRD: thread error detectors● Massif: heap profiler● ...

Page 4: T3-Valgrind

Memcheck

● Intercept calls to malloc/new/free/delete● Check all reads and writes of memory● Detect memory-management problems

○ buffer overflow○ memory leak ○ allocation/deallocation mismatch○ R/W via dangling pointer○ use uninitialized memory○ ...

Page 5: T3-Valgrind

A Bit of Internals

Valgrind is essentially a virtual machine● Translate machine code into an architecture-

independent intermediate representation● Insert instrumentation code around the IR

(depending on the tool)● Translating back into machine code and run

on a simulated CPUMemcheck: every register/memory value has a “shadow value” containing information about it

Page 6: T3-Valgrind

Get Valgrind

● Install Valgrind○ ecelinux has Valgrind pre-installed○ Ubuntu: apt-get install valgrind○ Archlinux: pacman -S valgrind○ General: ./configure & make & make install

Page 7: T3-Valgrind

Use Memcheck to Debug

● Compile your program○ $ gcc -g example.c -o example○ -g: include debug info. so Valgrind knows line # ○ -O: optimization, -O2 and above can screw up

Valgrind report, not recommended● Run Valgrind

○ $ valgrind ./exmaple○ Memcheck is the default tool invoked○ --leak-check=full: list details of each leak○ --track-origins=yes: track the origin of

uninitialized values○ others via valgrind --help

Page 8: T3-Valgrind

Buffer Overflow (Eg.1)

1 #include <stdio.h>

2 #include <stdlib.h>

3 int main()

4 {

5 int *b = calloc(

6 4, sizeof(int));

7 printf("%d\n", b[4]);

8 free(b);

9 return 0;

10 }

==31015== Invalid read of size 4

==31015== at 0x4005B0: main

(e1.c:7)

==31015== Address 0x51dc050 is 0

bytes after a block of

size 16 alloc'd

==31015== at 0x4C29860: calloc(in

/usr/lib/valgrind/

vgpreload_memcheck-

amd64-linux.so)

==31015== by 0x4005A3: main

(e1.c:5)

Page 9: T3-Valgrind

Memory Leak (Eg.2)

1 #include <stdio.h>

2 #include <stdlib.h>

3 int main()

4 {

5 int *b = calloc(

6 4, sizeof(int));

7 printf("%d\n", b[3]);

8 return 0;

9 }

==32266== 16 bytes in 1 blocks are

definitely lost in loss

record 1 of 1

==32266== at 0x4C29860: calloc

(in /usr/lib/valgrind/

vgpreload_memcheck-

amd64-linux.so)

==32266== by 0x400553: main

(e2.c:5)

==32266== LEAK SUMMARY:

==32266== definitely lost: 16

bytes in 1 blocks

...

Page 10: T3-Valgrind

Dangling Pointer (Eg.3) 1 #include <stdio.h>

2 #include <stdlib.h>

3 int main()

4 {

5 int *b = calloc(

6 4, sizeof(int));

7 b[2] = 1;

8 free(b);

9 printf("%d\n", b[2]);

10 return 0;

11 }

==5021== Invalid read of size 4

==5021== at 0x4005CA: main

(e3.c:9)

==5021== Address 0x51dc048 is 8

bytes inside a block of

size 16 free'd

==5021== at 0x4C289DC: free (in

/usr/lib/valgrind/

vgpreload_memcheck-

amd64-linux.so)

==5021== by 0x4005C1: main

(e3.c:8)

Page 11: T3-Valgrind

Double Free (Eg.4) 1 #include <stdio.h>

2 #include <stdlib.h>

3 int main()

4 {

5 int *b = malloc(

6 4 * sizeof(int));

7 b[2] = 1;

8 free(b);

9 free(b);

10 return 0;

11 }

==2819== Invalid free() / delete /

delete[] / realloc()

==2819== at 0x4C289DC: free (in

/usr/lib/valgrind/

vgpreload_memcheck-

amd64-linux.so)

==2819== by 0x400578: main (e4.c:9)

==2819== Address 0x51dc040 is 0 bytes

inside a block of size 16

free'd

==2819== at 0x4C289DC: free (in

/usr/lib/valgrind/

vgpreload_memcheck-

amd64-linux.so)

Page 12: T3-Valgrind

Uninitialized Memory (Eg.5) 1 #include <stdio.h>

2 #include <stdlib.h>

3 int main()

4 {

5 int ret;

6 int *b = malloc(

7 4 * sizeof(int));

8 ret = b[2];

9 free(b);

10 return ret;

11 }

==3911== Syscall param

exit_group(status) contains

uninitialised byte(s)

...

==3911== Uninitialised value was

created by a heap allocation

==3911== at 0x4C27730: malloc

(in /usr/lib/valgrind/

vgpreload_memcheck-

amd64-linux.so)

==3911== by 0x40054E: main

(e5.c:6)

Page 13: T3-Valgrind

Caveats

● No bound checking on stack-allocated arrays int main() {

int a[10];

a[11] = 42;

}

● More time (20x-30x), more memory (2x)● Reveal problem only when input triggering it

is provided

Page 14: T3-Valgrind

Useful Links

● Valgrind Quick Start Guide○ http://valgrind.org/docs/manual/quick-start.

html#quick-start.intro● Valgrind Memcheck Manual

○ http://valgrind.org/docs/manual/mc-manual.html● Design and Architecture of Valgrind

○ Nicholas Nethercote & Julian Seward, Valgrind: A Framework for Heavyweight Dynamic Binary Instrumentation, PLDI’07