Article Directory
principle
Memory leak concept
Memory leak : In computer science, the program's failure to release memory that is no longer used due to negligence or error is called a memory leak. Memory leak does not mean the physical disappearance of the memory, but after the application allocates a certain segment of memory, due to a design error, the program is not released, which causes a waste of memory.
Detection principle
To achieve memory leak detection, most likely to think that the program memory to operate (EG: 申请内存
, 释放内存
etc.) recorded during the control it when the program exits the application and release correspond get on, you can achieve memory leak detection. It is not difficult to say, but how do we monitor the operation of the program on the memory? This will be discussed in the specific way below.
So to extend it, how to detect it 野指针
?
According to my shallow knowledge, currently available only know 内存涂鸦
the way that each application memory, to be uninitialized graffiti on its content. If the pointer is found to be an uninitialized graffiti value when using the pointer, it is proved that the pointer is 野指针
.
In the same way, when we release the memory, we need to do memory graffiti on it, so that when we call the pointer again, we find that the memory it points to is graffitied 未初始化
, and we know that it is using a wild pointer.
As far as I know, some compilers do this, such as VC++ .
Method to realize
The above principle sounds easy, but how do you specifically record the memory operations of a program?
The simpler ones are the following three methods:
Overload
As we wrote in the program new
and delete
while we actually called is C++
built into the language new operator
and delete operator
. So that we can override new operator
and delete operator
to implement memory allocation and release the case of recording and analysis.
This method was mentioned in the previous blog post: C++-Overloaded Operators for Array Out-of-Bound Detection & Dividend Detection . Here I only inform you that you need to rewrite the following functions:
void* operator new( size_t nSize, char* pszFileName, int nLineNum )
void* operator new[]( size_t nSize, char* pszFileName, int nLineNum )
void operator delete( void *ptr )
void operator delete[]( void *ptr )
The shortcomings of this method are also obvious, it is just equivalent to encapsulating a layer of library functions. In this layer, the record analysis of the memory is realized.
For the original project (direct new operator
& delete operator
etc.) need to be new( )
, delete( )
such as a. A modification, only to realize memory test.
gcc_wrap
There is no way out of mountains and rivers
GCC reserved a back door for us, leaving us with an interesting option–wrap=symbol
We may call it 包装函数
; it can make the link in the link symbol符号
would search for when __wrap_symbol
, when will not find the original link symbol符号
.
Here is one demo
:
/* test.cpp */
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
extern "C"
{
int malloc_count = 0;
int free_count = 0;
void *__real_malloc(size_t size);
void __real_free(void *ptr);
void print_trace ();
void *__wrap_malloc(size_t size){
malloc_count++;
print_trace();
return __real_malloc(size);
}
void __wrap_free(void *ptr){
free_count++;
print_trace();
__real_free(ptr);
}
void *operator new(size_t size){
return __wrap_malloc(size);
}
void operator delete(void *ptr){
__wrap_free(ptr);
}
void print_trace ()
{
printf ("========== call stack =========\n");
void *array[10];
int size;
char **strings;
int i;
size = backtrace (array, 10);
strings = backtrace_symbols (array, size);
if (NULL != strings)
{
printf ("Obtained %zd stack frames.\n", size);
for (i = 0; i < size; i++)
{
printf ("%s\n", strings[i]);
}
__real_free(strings);
strings = NULL;
}
}
}
int main(){
int *p1 = (int*)malloc((sizeof(int)));
int *ptr1 = new int[5];
int *ptr2 = new int[5];
delete ptr1;
printf ("========== memory leak detection =========\n");
printf("malloc_count = %d\n",malloc_count);
printf("free_count = %d\n",free_count);
if(malloc_count != free_count){
printf("memony leak!\n");
}
return 0;
}
print_trace( )
Print stack, no need
Remember to bring that interesting option when compiling
gcc test.cpp -Wl,--wrap=malloc --wrap=free
LD_PRELOAD Steal the beam and change the column
Always felt that the use of gcc-wrap
the method also is not convenient enough, can not be packaged as so库
of any desired memory function detects the link compile it?
Reachable duck means: Yes
Prior to this, we first look at the Linux系统
loading so库
process:
Following switched Zheng Han Andrew_Hann - Linux System Calls Hooking Method Summary
Including Linux
systems, including many open-source systems are based on Glibc
dynamic links ELF可执行文件
will also launch at startup 动态链接器(/lib/ld-linux.so.X)
, the program relies on shared objects all by the dynamic linker is responsible for loading and initializing , so the search process here called shared libraries, nature The above is the search process of the shared library path by the dynamic linker (/lib/ld-linux.so.X) . The search process is as follows:
- /etc/ld.so.cache :
Linux
To speed upLD_PRELOAD
the search process, the establishment of a systemldconfig程序
, this program is responsible for:- Maintain each shared library under the shared library
SO-NAME
(one-to-one corresponding symbolic link), so that the SO-NAME of each shared library can point to the correct shared library file - All SO-NAME collected, concentrated into
/etc/ld.so.cache
a file inside, and create a buffer SO-NAME - When the dynamic linker wants to find a shared library, it can find it directly from /etc/ld.so.cache. So, if we add in the system specified shared library directory, delete or update any shared library, or we change
/etc/ld.so.conf
,/etc/ld.preload
configuration, should be run onceldconfig
this program to update the SO-NAME and /etc/ld.so. cache
- Maintain each shared library under the shared library
- Search (LD_PRELOAD) according to /etc/ld.so.preload configuration : the configuration file is saved in the shared library path to be searched, Linux dynamic loader shared libraries according to the order of progressive breadth search
- According to the dynamic library search path specified by the environment variable LD_LIBRARY_PATH
- According to the configuration information ELF file : Any dynamically linked modules depend module path stored in
".dynamic"段
the byDT_NEED
indicating the type of item, the dynamic linker will follow this path to findDT_RPATH
the time specified path, compiled object code, cangcc
Add link parameters to-Wl,-rpath
specify the dynamic library search path.- The absolute path is saved in the DT_NEED section, and the dynamic linker directly loads according to this path
- The relative path is saved in the DT_NEED section, and the dynamic linker will search the following paths for the library files in an agreed order
- /lib
- /usr/lib
- Configure the specified search path in /etc/ld.so.conf
Summary : you can see, LD_PRELOAD
it is Linux系统
the first to launch a new process 加载so
of the search path, so it can affect the operation of the program when the link ( Runtime linker
), which allows you to define before running "priority loading" dynamic link library.
We just by LD_PRELOAD
loading .so
the preparation we need hook
namesake functions, introduced into the process according to the global symbol table symbol Linux external dynamic shared library, after the introduction of the symbols will be omitted, i.e., the original system, .so(/lib64/libc.so.6)
the symbols will be omitted.
By strace program
can see, Linux
is a priority load LD_PRELOAD
specified .so
, then load the system default .so
is.
/* testmallic.cpp*/
#include <stdio.h>
#include <stdlib.h>
int malloc_count = 0;
int free_count = 0;
void printf_end();
void printf_end(){
fprintf(stderr,"=========Result=========\n");
fprintf(stderr,"malloc_count = %d\n",malloc_count);
fprintf(stderr,"free_count = %d\n",free_count);
if(malloc_count != free_count){
fprintf(stderr,"Memlook\n");
}
}
void* malloc(size_t size){
if(0 == malloc_count){
atexit(printf_end);
}
malloc_count ++;
fprintf(stderr,"malloc_count = %d\n",malloc_count);
return realloc(NULL,size);
}
void free(void *p){
free_count ++;
fprintf(stderr,"free_count = %d\n",free_count);
realloc(p,0);
}
Compiled to so库
g++ -shared -fpic -o testmallox.so testmallic.cpp
Write another test case
/*main.cpp*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *c1 = (char*)malloc(sizeof(char));
int *c2 = (int*)malloc(sizeof(int));
free(c1);
return 0;
}
Compile it
g++ -o main main.cpp
run
LD_PRELOAD=./testmalloc.so ./main