Linux memory leakage detection tool Valgrind
1 Overview 1.1 Introduction
Valgrind is a set of simulation debugging tools for open source code (GPL V2) in Linux. Valgrind consists of core and other kernel-based debugging tools. The kernel is similar to a framework. It simulates a CPU environment and provides services to other tools. Other tools are similar to plug-ins (plug-in ), use the services provided by the kernel to complete various memory debugging tasks. The architecture of Valgrind is shown in:
Figure 1
1.2 tools
The latest version of Valgrind is 3.11.0, which generally includes the following tools:
1. Memcheck
The most common tool used to detect memory problems in the program. All read/write operations on the memory will be detected, and all operations on the malloc ()/free () /new/delete calls will be captured. Therefore, it can detect the following problems:
Usage of uninitialized memory;
Read/write memory blocks released;
Read/write memory blocks beyond malloc allocation;
Memory blocks in the stack that are not suitable for reading/writing;
Memory leakage: the pointer pointing to a piece of memory is always lost;
Incorrect malloc/free or new/delete match;
The dst and src pointers in the memcpy () related functions overlap.
2. Callgrind
It is similar to gprof, but it is more subtle in program running observation, which can provide us with more information. Unlike gprof, it does not need to add special options when compiling the source code, but it is recommended to add debugging options. Callgrind collects some data when the program is running, establishes a function call relationship diagram, and can selectively simulate cache. At the end of the operation, it will write the analysis data into a file. Callgrind_annotate can convert the content of this file into a readable form.
3. Cachegrind
Cache analyzer, which simulates the level 1 cache I1, Dl, and level 2 Cache in the CPU, can accurately point out the loss and hit of the cache in the program. If needed, it can also provide us with the number of cache loss, memory reference times, and the number of commands generated by each code line, each function, each module, and the entire program. This is of great help to the optimization program.
4. Helgrind
It is mainly used to check competition problems in multi-threaded programs. Helgrind looks for areas in the memory that are accessed by multiple threads but are not always locked. These areas are often the places where synchronization is lost between threads and lead to undiscovered errors. Helgrind implements a competition detection algorithm named "Eraser" and further improves the algorithm to reduce the number of errors reported. However, Helgrind is still in the lab stage.
5. Massif
Stack analyzer, which can measure the memory used by the program in the stack, tells us the heap block, heap management block and stack size. Massif can help us reduce memory usage. In modern systems with virtual memory, it can also accelerate the running of our programs and reduce the chance that programs stay in the SWAp zone.
Lackey and nulgrind are also provided. Lackey is a small tool that is rarely used. Nulgrind only shows developers how to create a tool.
Principle 1.3
Memcheck can detect memory problems. The key is that it creates two Global tables. Valid-Value table
Each byte in the whole address space of the process has eight bits corresponding to it. Each register of the CPU also has a bit vector corresponding to it. These bits are responsible for recording whether the byte or register value has a valid and initialized value.
Valid-Address Table
For each byte in the process's entire address space, there is also a bit corresponding to it, which records whether the address can be read and written.
Detection principle:
When you want to read and write A byte in the memory, first check the bit corresponding to this byte. If this A bit shows that this location is invalid, memcheck reports A read/write error.
The core is similar to a virtual CPU environment, so that when a byte in the memory is loaded into the real CPU, the V bit corresponding to this byte is also loaded into the virtual CPU environment. Once the value in the register is used to generate a memory address, or this value can affect program output, memcheck checks the corresponding V bits. If the value has not been initialized, the uninitialized memory usage error is reported.
2. Use 2.1 for Installation
Download the latest version from http://www.valgrind.org (3.11 currently)
# Tar xvf valgrind-3.11.1.tar.bz2
# Cd valgrind-3.11.1
#./Configure -- prefix =/usr/local/valgrind -- specify the installation directory
# Make
# Make install
2.2 command Introduction
Usage: valgrind [options] prog-and-args [options]: common options for all Valgrind tools
- -Tool = <name> the most common options. Run the tool named toolname in valgrind. The default value is memcheck.
- H-help displays help information.
- -Version: the version of the valgrind kernel. Each tool has its own version.
- Q-quiet runs quietly and only prints error messages.
- V-verbose provides more detailed information and increases the number of errors.
- -Trace-children = no | yes trace sub-thread? [No]
- -Track-fds = no | yes trace the description of opened files? [No]
- -Time-stamp = no | yes, which increases the timestamp to LOG information? [No]
- -Log-fd = <number> output LOG to descriptor file [2 = stderr]
- -Log-file = <file> writes the output information to the file filename. PID. The PID is the ID of the running program.
- -Log-file-exactly = <file> output LOG information to file
- -Log-file-qualifier = <VAR> obtains the environmental variable value as the output file name. [None]
- -Log-socket = ipaddr: port: Output LOG to socket, ipaddr: port
LOG information output:
- -Xml = yes: the information is output in xml format, and only memcheck is available.
- -Num-callers = <number> show <number> callers in stack traces [12]
- -Error-limit = no | yes. If there are too many errors, the system stops displaying new errors? [Yes]
- -Error-exitcode = <number> if an error is found, the error code [0 = disable] is returned.
- -Db-attach = no | yes. When an error occurs, valgrind automatically starts the Debugger gdb. [No]
- -Db-command = <command> command line option for starting the debugger [gdb-nw % f % p]
Related options for Memcheck:
- -Leak-check = no | summary | what is the leak details required for full? [Summary]
- -Leak-resolution = low | med | high how much bt merging in leak check [low]
- -Show-reachable = no | yes show reachable blocks in leak check? [No]
3 Application practices
The following describes several examples to illustrate how to use Memcheck (other tools are not involved for the moment, and you can exchange them if you are interested). The example is for your reference only. More use cases can be continuously explored in practical applications.
3.1 array out-of-bounds/memory not released
# Include <stdlib. h>
Void k (void)
{
Int * x = malloc (8 * sizeof (int ));
X [9] = 0; // array subscript out of bounds
} // Memory not released
Int main (void)
{
K ();
Return 0;
}
1) Compile the program test. c.
Gcc-Wall test. c-g-o test # Wall prompts all alerts,-g gdb,-o output
2) use Valgrind to check program bugs
Valgrind -- tool = memcheck -- leak-check = full./test
# -- Leak-check = full all leak checks
3) The running result is as follows:
==2989 = Memcheck, a memory error detector
= 2989 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian Seward
Et al.
= 2989 = Using Valgrind-3.8.1 and LibVEX; rerun with-h
Copyright info
= 2989 = Command:./test
= 2989 =
==2989 = Invalid write of size 4
= 2989 = at 0x4004E2: k (test. c: 5)
==2989 = by 0x4004F2: main (test. c: 10)
==2989 = Address 0x4c27064 is 4 bytes after a block of size 32 alloc 'd
= 2989 = at 0x4A06A2E: malloc (vg_replace_malloc.c: 270)
= 2989 = by 0x4004D5: k (test. c: 4)
==2989 = by 0x4004F2: main (test. c: 10)
= 2989 =
= 2989 =
==2989 === heap summary:
= 2989 = in use at exit: 32 bytes in 1 blocks
= 2989 = total heap usage: 1 allocs, 0 frees, 32 bytes allocated
= 2989 =
==2989 = 32 bytes in 1 blocks are definitely lost in loss record 1
Of 1
= 2989 = at 0x4A06A2E: malloc (vg_replace_malloc.c: 270)
= 2989 = by 0x4004D5: k (test. c: 4)
==2989 = by 0x4004F2: main (test. c: 10)
= 2989 =
= 2989 = leak summary:
= 2989 = definitely lost: 32 bytes in 1 blocks
==2989 = indirectly lost: 0 bytes in 0 blocks
==2989 = possibly lost: 0 bytes in 0 blocks
= 2989 = still reachable: 0 bytes in 0 blocks
= 2989 = suppressed: 0 bytes in 0 blocks
= 2989 =
= 2989 = For counts of detected and suppressed errors, rerun with:-v
= 2989 = error summary: 2 errors from 2 contexts
(Suppressed: 6 from 6)
3.2 read/write after memory is released
# Include <stdio. h>
# Include <stdlib. h>
Int main (void)
{
Char * p = malloc (1); // allocation
* P = 'a ';
Char c = * p;
Printf ("\ n [% c] \ n", c );
Free (p); // release
C = * p; // Value
Return 0;
}
1) Compile the program t2.c
Gcc-Wall t2.c-g-o t2
2) use Valgrind to check program bugs
Valgrind -- tool = memcheck -- leak-check = full./t2
3) The running result is as follows:
==3058 = Memcheck, a memory error detector
= 3058 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian
Seward et al.
= 3058 = Using Valgrind-3.8.1 and LibVEX; rerun with-h
For copyright info
= 3058 = Command:./t2
= 3058 =
[A]
= 3058 = Invalid read of size 1
==3058 = at 0x4005A3: main (t2.c: 14)
==3058 = Address 0x4c27040 is 0 bytes inside a block of size
1 free 'd
= 3058 = at 0x4A06430: free (vg_replace_malloc.c: 446)
==3058 = by 0x40059E: main (t2.c: 13)
= 3058 =
= 3058 =
==3058 === heap summary:
= 3058 = in use at exit: 0 bytes in 0 blocks
= 3058 = total heap usage: 1 allocs, 1 frees, 1 bytes allocated
= 3058 =
= 3058 = All heap blocks were freed -- no leaks are possible
= 3058 =
= 3058 = For counts of detected and suppressed errors, rerun:
-V
= 3058 = error summary: 1 errors from 1 contexts
(Suppressed: 6 from 6)
From the output, Valgrind detects Invalid read operations and then outputs "Invalid read of size 1 ".
3.3 invalid read/write
# Include <stdio. h>
# Include <stdlib. h>
Int main (void)
{
Char * p = malloc (1); // allocate 1 byte
* P = 'a ';
Char c = * (p + 1); // Add 1 to the address
Printf ("\ n [% c] \ n", c );
Free (p );
Return 0;
}
1) Compile the program t3.c
Gcc-Wall t3.c-g-o t3
2) use Valgrind to check program bugs
Valgrind -- tool = memcheck -- leak-check = full./t3
3) The running result is as follows:
==3128 = Memcheck, a memory error detector
= 3128 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian Seward et al.
= 3128 = Using Valgrind-3.8.1 and LibVEX; rerun with-h for copyright info
= 3128 = Command:./t3
= 3128 =
==3128 = Invalid read of size 1 # Invalid read
==3128 = at 0x400579: main (t3.c: 9)
= 3128 = Address 0x4c27041 is 0 bytes after a block of size 1 alloc 'd
= 3128 = at 0x4A06A2E: malloc (vg_replace_malloc.c: 270)
= 3128 = by 0x400565: main (t3.c: 6)
= 3128 =
[]
= 3128 =
==3128 === heap summary:
= 3128 = in use at exit: 0 bytes in 0 blocks
= 3128 = total heap usage: 1 allocs, 1 frees, 1 bytes allocated
= 3128 =
= 3128 = All heap blocks were freed -- no leaks are possible
= 3128 =
= 3128 = For counts of detected and suppressed errors, rerun with:-v
= 3128 = error summary: 1 errors from 1 contexts
(Suppressed: 6 from 6)
3.4 Memory leakage
# Include <stdio. h>
# Include <stdlib. h>
Int main (void)
{
Int * p = malloc (1 );
* P = 'X ';
Char c = * p;
Printf ("% c \ n", c); // not released after application
Return 0;
}
1) Compile the program t4.c
Gcc-Wall t4.c-g-o t4
2) use Valgrind to check program bugs
Valgrind -- tool = memcheck -- leak-check = full./t4
3) The running result is as follows:
==3221 = Memcheck, a memory error detector
= 3221 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian Seward et al.
= 3221 = Using Valgrind-3.8.1 and LibVEX; rerun with-h for copyright info
= 3221 = Command:./t4
= 3221 =
==3221 = Invalid write of size 4
= 3221 = at 0x40051E: main (t4.c: 7)
= 3221 = Address 0x4c27040 is 0 bytes inside a block of size 1 alloc 'd
= 3221 = at 0x4A06A2E: malloc (vg_replace_malloc.c: 270)
= 3221 = by 0x400515: main (t4.c: 6)
= 3221 =
= 3221 = Invalid read of size 4
==3221 = at 0x400528: main (t4.c: 8)
= 3221 = Address 0x4c27040 is 0 bytes inside a block of size 1 alloc 'd
= 3221 = at 0x4A06A2E: malloc (vg_replace_malloc.c: 270)
= 3221 = by 0x400515: main (t4.c: 6)
= 3221 =
X
= 3221 =
==3221 === heap summary:
= 3221 = in use at exit: 1 bytes in 1 blocks
= 3221 = total heap usage: 1 allocs, 0 frees, 1 bytes allocated
= 3221 =
= 3221 = 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
= 3221 = at 0x4A06A2E: malloc (vg_replace_malloc.c: 270)
= 3221 = by 0x400515: main (t4.c: 6)
= 3221 =
= 3221 = leak summary:
= 3221 = definitely lost: 1 bytes in 1 blocks
==3221 = indirectly lost: 0 bytes in 0 blocks
==3221 = possibly lost: 0 bytes in 0 blocks
= 3221 = still reachable: 0 bytes in 0 blocks
= 3221 = suppressed: 0 bytes in 0 blocks
= 3221 =
= 3221 = For counts of detected and suppressed errors, rerun with:-v
= 3221 = error summary: 3 errors from 3 contexts
(Suppressed: 6 from 6)
According to the check results, memory leakage can be found.
3.5 memory released multiple times
# Include <stdio. h>
# Include <stdlib. h>
Int main (void)
{
Char * p;
P = (char *) malloc (100 );
If (p)
Printf ("Memory Allocated at: % s/n", p );
Else
Printf ("Not Enough Memory! /N ");
Free (p); // release again
Free (p );
Free (p );
Return 0;
}
1) Compile the program t5.c
Gcc-Wall t5.c-g-o t5
2) use Valgrind to check program bugs
Valgrind -- tool = memcheck -- leak-check = full./t5
3) The running result is as follows:
==3294 = Memcheck, a memory error detector
= 3294 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian Seward
Et al.
= 3294 = Using Valgrind-3.8.1 and LibVEX; rerun with-h
Copyright info
= 3294 = Command:./t5
= 3294 =
= 3294 = Conditional jump or move depends on uninitialised value (s)
= 3294 = at 0x3CD4C47E2C: vfprintf (in/lib64/libc-2.12.so)
= 3294 = by 0x3CD4C4F189: printf (in/lib64/libc-2.12.so)
= 3294 = by 0x400589: main (t5.c: 9)
= 3294 =
==3294 = Invalid free ()/delete []/realloc ()
= 3294 = at 0x4A06430: free (vg_replace_malloc.c: 446)
==3294 = by 0x4005B5: main (t5.c: 13)
==3294 = Address 0x4c27040 is 0 bytes inside a block of size
100 free 'd
= 3294 = at 0x4A06430: free (vg_replace_malloc.c: 446)
= 3294 = by 0x4005A9: main (t5.c: 12)
= 3294 =
==3294 = Invalid free ()/delete []/realloc ()
= 3294 = at 0x4A06430: free (vg_replace_malloc.c: 446)
==3294 = by 0x4005C1: main (t5.c: 14)
==3294 = Address 0x4c27040 is 0 bytes inside a block of size
100 free 'd
= 3294 = at 0x4A06430: free (vg_replace_malloc.c: 446)
= 3294 = by 0x4005A9: main (t5.c: 12)
= 3294 =
Memory Allocated at:/n = 3294 =
==3294 === heap summary:
= 3294 = in use at exit: 0 bytes in 0 blocks
= 3294 = total heap usage: 1 allocs, 3 frees, 100 bytes allocated
From the above output, we can see (annotation). This function detects that we have called the same pointer three times to release the memory.
3.6 dynamic memory management
There are three common memory allocation methods: static storage, stack allocation, and stack allocation. Global variables belong to static storage. They are allocated storage space during compilation, and local variables in the function belong to stack allocation. The most flexible memory usage is allocated on the stack, it is also called dynamic memory allocation. Common memory dynamic allocation functions include malloc, alloc, realloc, and new. Dynamic Release functions include free and delete.
Once dynamic memory is successfully applied for, we need to manage the memory on our own, which is the easiest way to make mistakes. The following program contains common errors in dynamic memory management.
# Include <stdio. h>
# Include <stdlib. h>
Int main (int argc, char * argv [])
{
Int I;
Char * p = (char *) malloc (10 );
Char * pt = p;
For (I = 0; I <10; I ++)
{
P [I] = 'Z ';
}
Free (p );
Pt [1] = 'X ';
Free (pt );
Return 0;
}
1) Compile the program t6.c
Gcc-Wall t6.c-g-o t6
2) use Valgrind to check program bugs
Valgrind -- tool = memcheck -- leak-check = full./t6
3) The running result is as follows:
==3380 = Memcheck, a memory error detector
= 3380 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian Seward et al.
= 3380 = Using Valgrind-3.8.1 and LibVEX; rerun with-h for copyright info
= 3380 = Command:./t6
= 3380 =
==3380 = Invalid write of size 1
==3380 = at 0x40055C: main (t6.c: 14)
= 3380 = Address 0x4c27041 is 1 bytes inside a block of size 10 free 'd
= 3380 = at 0x4A06430: free (vg_replace_malloc.c: 446)
= 3380 = by 0x400553: main (t6.c: 13)
= 3380 =
==3380 = Invalid free ()/delete []/realloc ()
= 3380 = at 0x4A06430: free (vg_replace_malloc.c: 446)
==3380 = by 0x40056A: main (t6.c: 15)
= 3380 = Address 0x4c27040 is 0 bytes inside a block of size 10 free 'd
= 3380 = at 0x4A06430: free (vg_replace_malloc.c: 446)
= 3380 = by 0x400553: main (t6.c: 13)
= 3380 =
= 3380 =
==3380 === heap summary:
= 3380 = in use at exit: 0 bytes in 0 blocks
= 3380 = total heap usage: 1 allocs, 2 frees, 10 bytes allocated
Release after the application is used. If it is not released, or if it is released less, memory leakage occurs. If it is released more, problems may occur. In the above program, the pointer p and pt point to the same memory, but are released twice. The system will maintain a dynamic memory linked list on the stack. If it is released, it means that the block of memory can continue to be allocated to other parts. If the memory is released and then accessed, it is possible to overwrite the information of other parts. This is a serious error. The above program will still write this memory after it is released in line 1.
The output results show that the allocation and release functions of Row 3 are inconsistent. The write operation of Row 3 is invalid, that is, the write value to the released memory address. The memory function of Row 3 is invalid.
Valgrind * is not * a leak check tool
Usage of Valgrind in Linux
Use Valgrind in Linux for Memory leakage detection and Performance Analysis
Install Ubuntu memory leak detection tool Valgrind
Valgrind-memory debugging and code anatomy tools in Linux
Use Valgrind to discover memory problems in Linux programs [graphic]
This article permanently updates the link address: