Detection of memory leaks in Linux (v) code to record memory leaks

Source: Internet
Author: User

So far, the need for memory leak detection has been largely met by the method of wrap malloc, new function overloading, and calculation of pointer memory size.

If a memory leak is found, then find out where the memory leaks are and fix it.

Boundless code, how to find? It would be nice if we could find the place to apply it based on the memory that was not released.

We are going to do it today.

To identify the applicant's information based on the memory address, the mapping between the address and the applicant should be established at the beginning of the application.

1. Memory address

Memory address, is a unsigned long value, used void * to store also can. In order to avoid type conversions, I used the void * .

2. Applicants ' information

The applicant's information is more complex, not a type can be done. What does it include?

In the case of C, it is important to know who called it __wrap_malloc . But in the case of C + +, the call __wrap_malloc must be new, which doesn't make sense, and you need to know who called New. Further, new is probably called in the constructor, so it is very likely that we really need to know who called the constructor.

This shows that just knowing who is calling is __wrap_malloc not enough, what we need is the entire stack of information.

The entire stack contains a lot of content, where we only record the depth (int) of the stack and the symbol name of each layer (char * *). The symbol name is unique throughout the program (whether C or C + +) and the relative position is deterministic (except for the dynamic library), and when the program ends, the caller's file name and line number are re-introduced according to the symbol name.

Why not get the file name and line number directly?
Because the implementation of the symbol name is relatively simple.

3. Mapping method

When it comes to mapping, the first thing to think about is map, hash, and so on.

However, it is necessary to note that this is a __wrap_malloc function that is bound to go where each program dynamically allocates space.

What does it matter? Imagine what it would be like to have a dynamic request for memory to come into this function and accidentally apply a memory in this function. In -Wl,--wrap,malloc the role of coming here again, so opened the "chicken eggs, eggs and chickens" in the death cycle, until--stack overflow.

Therefore, in this function can use only the stack space or global space, if you must use heap space, also must be shown to use instead of __real_malloc new or malloc. Because of the inevitable use of dynamic memory space in map, hash, or discard it.

What do we do? To avoid complications, I used the simplest but somewhat stupid method-arrays.

struct memory_record{    void * addr;    size_t count;    int depth;    char **symbols;}mc[1000];

4. How do I get the symbols in the stack?

GCC gives us the appropriate function to call on the line as required.

char  * stack  [20 ] = {0 };mc[i]. depth = BackTrace (reinterpret_cast  <void  * * > (stack ), sizeof  ( stack ) /sizeof  (stack  [0 ])); if  (mc[i].depth) {mc[i].symbols = Backtrace_symbols (reinterpret_cast  < void  **> (stack ), mc[i].depth); }

The BackTrace function is used to get the depth () of the stack depth , as well as the stack address () for each layer stack .
backtrace_symbolsThe function returns the symbol name () based on the stack address symbols .
It is important to note that Backtrace_symbols returns an array of symbols, the space of this array is backtrace_symbols allocated by the caller but needs to be freed.

Why backtrace_symbols is the memory allocated here without causing stack overflow? Here's my guess:
backtrace_symbolsThe functions and wrap mechanisms are all provided by the GNU, attribute relatives. Since it is a relative, it is possible to make backtrace_symbols use of the memory directly by bypassing the wrap mechanism.

Source:

#include <iostream>using namespace STD;#include "string.h"#include <stdio.h>#include <malloc.h>#include <execinfo.h>#if (defined (_x86_) &&!defined (__x86_64))#define _ALLOCA_S_MARKER_SIZE 4#elif defined (__ia64__) | | defined (__X86_64)#define _ALLOCA_S_MARKER_SIZE 8#endifsize_t count =0;intBackTrace (void**buffer,intsize);structmemory_record{void* ADDR; size_t count;intDepthChar**symbols;} mc[ +];extern "C"{void* __REAL_MALLOC (intc);void* __WRAP_MALLOC (size_t size) {void*p = __real_malloc (size); size_t w = * ((size_t*) ((Char*) (P-_alloca_s_marker_size));cout<<"malloc"<<p<<endl; for(inti =0; I < +; i++) {if(Mc[i].count = =0) {count + = W;            MC[I].ADDR = p; Mc[i].count = W;Char*Stack[ -] = {0}; Mc[i].depth = BackTrace (reinterpret_cast<void**> (Stack),sizeof(Stack)/sizeof(Stack[0]));if(mc[i].depth) {Mc[i].symbols = Backtrace_symbols (reinterpret_cast<void**> (Stack), mc[i].depth); } Break; }    }returnP;}void__real_free (void*PTR);void__wrap_free (void*PTR) {cout<<"Free"<<ptr<<endl; size_t w = * ((size_t*) ((Char*) (PTR-_alloca_s_marker_size)); for(inti =0; I < +; i++) {if(mc[i].addr = = ptr)            {Mc[i].count-= W; Count-= W;if(mc[i].symbols) __real_free (mc[i].symbols); Break; }} __real_free (PTR);}}void*operator New(size_t size) {return malloc(size);}void operator Delete(void*PTR) { Free(PTR);}voidPrint_leaked_memory () {if(Count! =0)cout<<"Memory leak!"<<endl; for(inti =0; I < +; i++) {if(Mc[i].count! =0)         {cout<<mc[i].addr<<"'<<mc[i].count<<endl;if(Mc[i].symbols) { for(size_t j =0; J < Mc[i].depth; J + +) {printf("===[%d]:%s\n", (j+1), Mc[i].symbols[j]);         }} __real_free (Mc[i].symbols); }     }}classa{int*P1; Public: A () {p1 =New int;} ~a () {Deletep1;}};intMainvoid){memset(MC,0,sizeof(MC)); Count =0;int*P1 =New int(4);int*P2 =New int(5);DeleteP1; Print_leaked_memory ();return 0;}

Compile command:

g++-o test test.-g-Wl,---Wl,--wrap,free

Run:

"==="-d"["-f-d"]"-e test

Method Analysis:

Advantages:

(1) At the end of the program run, the print program memory leaks and the code that causes the leak occurs the file and line number

(2) C + + is applicable

(3) Need to modify the product source code to achieve the function

(4) all. O and static libraries are valid for all links.

Disadvantages:

(1) Not applicable to dynamic library

(2) The stack information and the file name line number is two operations, can not solve the problem at once

Detection of memory leaks in Linux (v) code to record memory leaks

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.