How do I use valgrind to find memory leaks?

匿名 (未验证) 提交于 2019-12-03 08:36:05

问题:

How do I use valgrind to find the memory leaks in a program?

Please someone help me and describe the steps to carryout the procedure?

I am using Ubuntu 10.04 and I have a program a.c, please help me out.

回答1:

Try this:

valgrind --leak-check=full -v ./your_program

As long as valgrind is installed it will go through your program and tell you what's wrong. It can give you pointers and approximate places where your leaks may be found. If you're segfault'ing, try running it through gdb.



回答2:

How to Run Valgrind

I would like to build on RageD's great answer by providing a more verbose explanation for how to use Valgrind effectively and how to resolve memory leaks. Not to insult the OP, but for those who come to this question and are still new to Linux -- you might have to install Valgrind on your system.

sudo apt-get install valgrind #mainly Ubuntu sudo yum install valgrind     #RHEL, CentOS, Fedora, etc. 

Valgrind is readily usable for C/C++ code, but can even be used for other languages when configured properly (see this for Python).

To run valgrind, pass the executable as an argument (along with any parameters to the program).

valgrind --leak-check=full \          --show-leak-kinds=all \          --track-origins=yes \          --verbose \          --log-file=valgrind-out.txt \          ./executable exampleParam1 

This will produce a report at the end of executing your program that (hopefully) looks like this:

HEAP SUMMARY:     in use at exit: 0 bytes in 0 blocks   total heap usage: 636 allocs, 636 frees, 25,393 bytes allocated  All heap blocks were freed -- no leaks are possible  ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

I have a leak, but WHERE?

So, you have a memory leak, and Valgrind isn't saying anything meaningful. Perhaps, something like this:

5 bytes in 1 blocks are definitely lost in loss record 1 of 1    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)    by 0x40053E: main (in /home/Peri461/Documents/executable) 

Let's take a look at the C code I wrote too:

#include   int main() {     char* string = malloc(5 * sizeof(char)); //ERROR: not freed!     return 0; } 

Well, there were 5 bytes lost. How did it happen? The error report just says main and malloc. In a larger program, that would be seriously troublesome to hunt down. This is because of how the executable was compiled. We can actually get line-by-line details on what went wrong. Recompile your program with a debug flag (I'm using gcc here):

gcc -o executable -std=c11 -Wall main.c #suppose it was this at first gcc -o executable -std=c11 -Wall -ggdb3 main.c #add -ggdb3 to it 

Now look at what Valgrind did with our debug build:

5 bytes in 1 blocks are definitely lost in loss record 1 of 1    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)    by 0x40053E: main (main.c:4) 

Valgrind pointed us to the exact line of code causing the memory leak!


Techniques for Debugging Memory Leaks & Errors

  • Make use of www.cplusplus.com! It has great documentation on C/C++ functions.
  • General advice for memory leaks:
    • Make sure your dynamically allocated memory does in fact get freed.
    • Don't allocate memory and forget to assign the pointer.
    • Don't overwrite a pointer with a new one unless the old memory is freed.
  • Sometimes Valgrind doesn't always point exactly to where your error is. Sometimes you have a lot of errors and resolving one of them resolves a cascade of others.
    • List out the functions in your code that depend on/are dependent on the "offending" code that has the memory error. Follow the program's execution (maybe even in gdb perhaps), and look for precondition/postcondition errors.
    • Try commenting out the "offending" block of code (within reason, so your code still compiles). If the Valgrind error goes away, you've found where it is.
  • If all else fails, try looking it up. Valgrind has documentation too!

A Look at Common Leaks and Errors

Watch your pointers

60 bytes in 1 blocks are definitely lost in loss record 1 of 1    at 0x4C2BB78: realloc (vg_replace_malloc.c:785)    by 0x4005E4: resizeArray (main.c:12)    by 0x40062E: main (main.c:19) 

And the code:

#include  #include   struct _List {     int32_t* data;     int32_t length; }; typedef struct _List List;  List* resizeArray(List* array) {     int32_t* dPtr = array->data;     dPtr = realloc(dPtr, 15 * sizeof(int32_t)); //doesn't update array->data     return array; }  int main() {     List* array = calloc(1, sizeof(List));     array->data = calloc(10, sizeof(int32_t));     array = resizeArray(array);      free(array->data);     free(array);     return 0; } 

As a teaching assistant, I've seen this mistake often. The student makes use of a local variable and forgets to update the original pointer. The error here is noticing that realloc can actually move the allocated memory somewhere else and change the pointer's location. We then leave resizeArray without telling array->data where the array was moved to.

Invalid write

1 errors in context 1 of 1: Invalid write of size 1    at 0x4005CA: main (main.c:10)  Address 0x51f905a is 0 bytes after a block of size 26 alloc'd    at 0x4C2B975: calloc (vg_replace_malloc.c:711)    by 0x400593: main (main.c:5) 

And the code:

#include  #include   int main() {     char* alphabet = calloc(26, sizeof(char));      for(uint8_t i = 0; i 

Notice that Valgrind points us to the commented line of code above. The array of size 26 is indexed [0,25] which is why *(alphabet + 26) is an invalid write -- it's out of bounds. An invalid write is a common result of off-by-one errors. Look at the left side of your assignment operation.

Invalid read

1 errors in context 1 of 1: Invalid read of size 1    at 0x400602: main (main.c:9)  Address 0x51f90ba is 0 bytes after a block of size 26 alloc'd    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)    by 0x4005E1: main (main.c:6) 

And the code:

#include  #include   int main() {     char* destination = calloc(27, sizeof(char));     char* source = malloc(26 * sizeof(char));      for(uint8_t i = 0; i 

Valgrind points us to the commented line above. Look at the last iteration here, which is *(destination + 26) = *(source + 26);. However, *(source + 26) is out of bounds again, similarly to the invalid write. Invalid reads are also a common result of off-by-one errors. Look at the right side of your assignment operation.



回答3:

You can run:

valgrind --leak-check=full --log-file="logfile.out" -v [your_program(and its arguments)] 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!