[Code Quality] How to use Valgrind to detect memory leaks



1 Introduction

  Compared with other high-level programming languages, C/C++ has the concept of pointers, which are memory addresses. C/C++ can directly access the memory space through pointers. The improvement in efficiency is self-evident and is unmatched by other high-level programming languages; for example, when accessing a piece of data in memory, data can be directly read from the memory space through pointers to avoid In the middle of the process, function stacking, data copying and even message transmission waiting. Pointers are the advantage of C/C++, but they are also a hidden danger. Pointers are a double-edged sword. Since memory is handed over to the programmer to manage, there are hidden dangers; when people are always negligent, if they apply for memory, If you forget to release it by negligence, the unreleased memory will not be used by the system again, that is, it has been occupied but cannot be used, commonly known as memory leak; over time, the system will not be able to apply for memory after a long time running, and all tasks on the system will fail. Only restart the system. The memory is handed over to the programmer to manage. In addition to memory leaks, other problems may also be caused. In summary, the following points are included.

  • Access to a null pointer (null pointer) that has not applied for memory
  • A pointer to access the released memory (wild pointer)
  • Out of bounds memory access
  • Memory leak, memory is not released after application
  • Release memory repeatedly

  Although dynamic memory (here by default refers to dynamic memory on the heap, managed by the programmer; dynamic memory on the stack is managed by the system) has certain hidden dangers, and reliability depends on the programmer's seriousness and care, but because it has excellent In practical applications, dynamic memory is often the first choice for some dynamic data interaction occasions. Therefore, on the one hand, in addition to the cautious use of programmers themselves, on the other hand, various "memory anomaly" detection tools have also emerged. After all, when the amount of code is tens of thousands of hours, it is impractical to rely on manpower to check.


2 Common memory detection tools

  Although there are hidden dangers in dynamic memory, sometimes it has to be used. Memory leakage has become a sensitive problem that must be eliminated; there will be corresponding solutions when there is a demand. There are many excellent memory leakage detection tools, except for our commonly used In addition to Valgrind, there are also excellent tools such as mtrace, dmalloc, and memwatch.

tool description
valgrind A powerful open source program detection tool collection
mtrace GNU extension, used to track malloc, mtrace installs hook functions for memory allocation functions (malloc, realloc, memalign, free)
dmalloc A tool for checking C/C++ memory leaks (leak), that is, checking whether there is memory that has not been released until the end of the program, and it is released as a runtime library
memwatch Like dmalloc, it can detect unreleased memory, the same memory has been released multiple times, address access errors, and improper use of unallocated memory areas
mpatrol A cross-platform C++ memory leak detector
dbgmem
Electric Fence

3 Valgrind tools

  Valgrind is a collection of open source memory detection tools based on the Linux platform, powerful and widely used. Use the Valgrind tool to detect the hidden danger of dynamic memory mentioned at the beginning of the article, that is, the memory detection component Memcheck in the Valgrind tool. The functions supported by Memcheck include:

  • Use a null pointer
  • Use wild pointer
  • Memory space access out of bounds
  • Memory space is not released
  • Repeated release of memory space
  • Memory space application and release do not match

  Valgrind is powerful and is a collection of tools. In addition to Memcheck tools, it also provides Cachegrind, Helgrind, Callgrind, and Massif tools.

  • Cachegrind

  An analysis tool similar to gprof, but its observation of the operation of the program is more subtle and can provide us with more information. Unlike gprof, it does not require 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 graph, and optionally performs cache simulation. At the end of the run, it will write the analysis data to a file. callgrind_annotate can convert the content of this file into a readable form.


  • Helgrind

   Cache analyzer, which simulates the first-level cache I1, Dl and the second-level cache in the CPU, can accurately point out the cache miss and hit in the program. If necessary, it can also provide us with the number of cache misses, the number of memory references, and the number of instructions generated by each line of code, each function, each module, and the entire program. This is a great help to optimize the program.


  • Callgrind

  It is mainly used to check competition problems in multithreaded programs. Helgrind looks for areas in the memory that are accessed by multiple threads and are not consistently locked. These areas are often places where threads are out of synchronization and can lead to errors that are difficult to discover. Helgrind implemented a competition detection algorithm called "Eraser" and made further improvements to reduce the number of errors reported. However, Helgrind is still in the experimental stage.


  • Massif

   Stack analyzer, it can measure how much memory the program uses in the stack, tell us the heap block, heap management block and stack size. Massif can help us reduce the use of memory. In modern systems with virtual memory, it can also speed up the running of our programs and reduce the chance of programs staying in the swap area.


  • extension

  You can write custom memory debugging tools based on the functions provided by core.


  The above tool set introduction is quoted from the article on memory leak checking tools in several C++ programs under Linux . The updated detailed introduction can be read in the original text, and the summary is very good.


4 Use Valgrind tool to detect memory

  The principle of Valgrind memory detection is that Valgrind implements a virtual environment where the program runs. The application to be tested runs in Valgrind's virtual environment. Valgrind can monitor the application, use, and release of the memory in the program in real time, and record some normal running Valid information and information that may have memory abnormalities are output to the terminal or a file specified by the user.


4.1 Valgrind installation

  The Valgrind tool is practical and widely used. Most mainstream Linux system distributions have integrated the Valgrind tool. Input at the terminal “valgrind”. If the Valgrind tool is not installed in the system, the following installation information will be prompted.

acuity@ubuntu:~$ valgrind 
The program 'valgrind' is currently not installed. You can install it by typing:
sudo apt install valgrind

  Valgrind installation can be installed after downloading the source code, or online installation through the system source, Ubuntu recommends online installation.

sudo apt install valgrind

  After the installation is complete, enter the “valgrind”command and prompt the following information, indicating that the installation is successful.

acuity@ubuntu:~$ valgrind
valgrind: no program specified
valgrind: Use --help for more information.

4.2 Instructions for use

  • The program to be tested needs to be added when compiling, "-g"and the debugging information is retained
  • Detection command format: valgrind --tool=memcheck --leak-check=full ./file, –leak-check=fullindicating the detection of all memory leaks
  • In addition to outputting the detection record to the terminal, it can also be output to a file, so that you can monitor the abnormality after the program runs for a long time, and analyze the problem by consulting the file record
  • More instructions or when you forget the command, you can execute to valgrind -hview the help information

4.3 The test program uses a null pointer

Examples uninit.c:

#include <stdio.h>

int main(int argc, char * argv [ ])
{
    
    	
	int *p = NULL;

    printf("address [0x%p]\r\n", p);
	*p = 0;
	
    return 0;
}

Insert picture description here

  Accessing the null pointer, especially when writing data to the null pointer, will basically cause a segmentation fault (Segmentation fault). At this time, the system will generate a core dump file. It is also easy to find out where the null pointer is accessed through the core dump file combined with the GDB tool.


4.4 The detection program uses wild pointers

Examples free.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv [ ])
{
    
    	
	int *p = NULL;

	p = malloc(4);
	if (p == NULL)
	{
    
    
		perror("malloc failed");
	}
    printf("address [0x%p]\r\n", p);
	free(p);
	*p = 0;
	
    return 0;
}

Insert picture description here


4.5 Detection of out-of-bounds access to program memory space

Examples over.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv [ ])
{
    
    	
	int *p = NULL;

	p = malloc(4);
	if (p == NULL)
	{
    
    
		perror("malloc failed");
	}
    printf("address [0x%p]\r\n", p);
	p[4] = 0;
	free(p);
	
    return 0;
}

Insert picture description here

4.6 Check that the program memory space is not released

Examples leak.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv [ ])
{
    
    	
	int *p = NULL;

	p = malloc(4);
	if (p == NULL)
	{
    
    
		perror("malloc failed");
	}
    printf("address [0x%p]\r\n", p);

    return 0;
}

Insert picture description here

4.7 Detection of repeated release of program memory space

Examples refree.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv [ ])
{
    
    	
	int *p = NULL;

	p = malloc(4);
	if (p == NULL)
	{
    
    
		perror("malloc failed");
	}
    printf("address [0x%p]\r\n", p);
	free(p);
	free(p);
	
    return 0;
}

Insert picture description here

4.8 Detection of mismatch between application and release of program memory space

Examples nolike.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv [ ])
{
    
    	
	int *p = NULL;

	p = (int*)malloc(sizeof(int));
	if (p == NULL)
	{
    
    
		perror("malloc failed");
	}
    printf("address [0x%p]\r\n", p);
	delete p;
	
    return 0;
}

Insert picture description here


4.9 Summary

  Memory leak detection includes the standardization of dynamic memory usage. The fundamental solution is that programmers maintain good coding habits, carefully consider when using dynamic memory, and ensure the inevitability of application and release. Because some obscure problems may only cause memory leaks under certain conditions, and relying on detection tools also require long-running software to discover.

  Valgrind-memcheck tool is more used to detect memory leaks, null pointers, wild pointers, memory out of bounds, repeated releases, etc., which will cause system segmentation faults (Valgrind). Using GDB combined with the core dump file generated by the system can also quickly locate Go to the calling location. And memory leaks will not cause system exceptions immediately, and will only cause exceptions when the system cannot apply for memory after running for a certain period of time. Therefore, using the Valgrind-memcheck tool to detect memory leaks is one of the efficient methods.


5 Reference articles

[1] Memory leak check tools in several C++ programs under Linux

[2] Valgrind study summary

Guess you like

Origin blog.csdn.net/qq_20553613/article/details/106503929