不改动已存在代码,程序退出时检测内存泄露 .

来源:互联网 发布:淘宝氛围图是什么样的 编辑:程序博客网 时间:2024/06/08 20:06

尽管-rdynamic选项使得可读性大大提高,但仍然不太好根据二进制地址定位到某行泄露代码;

这时使用objdump  -S  exefile 即可)


在WINDOWS下检测内存泄露比较容易,毕竟MSDN强大,方法多多;有兴趣可以查看VLD源代码;

  前几天无意中从MAN文档中查到linux可以给malloc挂钩子;于是写下了如下检测内存泄露的代码;

已存在的程序代码只需要与linux_vld.o文件一起编译链接即可,退出时会打印内存泄露状态;


对于下面文件,g++ -c linux_vld.cc得到o文件即可;

[cpp] view plaincopyprint?
  1. #ifndef LINUX_VLD_H   
  2. #define LINUX_VLD_H   
  3.   
  4. #include <stdlib.h>   
  5. #include <malloc.h>   
  6.   
  7.   
  8. #endif  


[cpp] view plaincopyprint?
  1. #include <map>   
  2. #include <vector>   
  3. #include <string>   
  4. #include <execinfo.h>   
  5. #include <cxxabi.h>   
  6.   
  7. #include "linux_vld.h"   
  8.   
  9. static void *(*old_malloc_hook)(size_tconst void*);  
  10. static void (*old_free_hook)(void*, const void*);  
  11. static void *(*old_realloc_hook)(void*, size_tconst void*);  
  12.   
  13. static void ReportMemoryLeak(void);  
  14. static void MyHookInit(void);  
  15. static void MyHookUnInit(void);  
  16.   
  17. static void* MyMallocHook(size_tconst void* );  
  18. static void* MyReallocHook(void* , size_t , const void* );  
  19. static void  MyFreeHook(void* , const void* );  
  20.   
  21. typedef struct  
  22. {  
  23.     std::size_t  size;  
  24.     std::vector<std::string>  stackinfo;  
  25. } NODE;  
  26.   
  27. static  std::map<void*, NODE>   s_ptrContainer;  
  28. typedef std::map<void*, NODE>::iterator ITER;  
  29.   
  30. namespace  
  31. {  
  32.   
  33.     class HookGuard  
  34.     {  
  35.     private:  
  36.         static HookGuard sm_guard;  
  37.         HookGuard();  
  38.   
  39.     public:  
  40.         ~HookGuard();  
  41.     };  
  42.   
  43.     // Hook init in constructor  
  44.     HookGuard   HookGuard::sm_guard;  
  45.   
  46.     HookGuard::HookGuard()  
  47.     {  
  48.         __malloc_initialize_hook = &MyHookInit;  
  49.         atexit(&ReportMemoryLeak);  
  50.     }  
  51.   
  52.     HookGuard::~HookGuard()   
  53.     {  
  54.         MyHookUnInit();  
  55.     }  
  56. // end namespace   
  57.   
  58. static void* MyMallocHook(size_t size, const void* caller)  
  59. {  
  60.     MyHookUnInit();  
  61.   
  62.     void* pResult = ::malloc(size);  
  63.   
  64.     if (NULL != pResult)  
  65.     {  
  66.         NODE    node;  
  67.         void*   arr[32];  
  68.         int     nFrames= ::backtrace(arr, sizeof(arr)/sizeof(arr[0]));  
  69.         char** strings = ::backtrace_symbols(arr, nFrames);  
  70.         if (NULL != strings)  
  71.         {  
  72.             node.stackinfo.reserve(nFrames);  
  73.             for (int i = 0; i < nFrames; ++ i)  
  74.             {  
  75.                 node.stackinfo.push_back(strings[i]);  
  76.             }  
  77.             ::free(strings);  
  78.         }  
  79.   
  80.         node.size = size;  
  81.         s_ptrContainer[pResult] = node;  
  82.     }  
  83.   
  84.     MyHookInit();  
  85.   
  86.     return  pResult;  
  87. }  
  88.   
  89. static void* MyReallocHook(void* ptr, size_t size, const void* caller)  
  90. {  
  91.     MyHookUnInit();  
  92.   
  93.     const bool isFree(ptr != NULL && size == 0);  
  94.   
  95.     void* pResult = ::realloc(ptr, size);  
  96.   
  97.     if (NULL != pResult)  
  98.     {  
  99.         NODE    node;  
  100.         void*   arr[32];  
  101.         int     nFrames= ::backtrace(arr, sizeof(arr)/sizeof(arr[0]));  
  102.         char** strings = ::backtrace_symbols(arr, nFrames);  
  103.         if (NULL != strings)  
  104.         {  
  105.             node.stackinfo.reserve(nFrames);  
  106.             for (int i = 0; i < nFrames; ++ i)  
  107.             {  
  108.                 node.stackinfo.push_back(strings[i]);  
  109.             }  
  110.             ::free(strings);  
  111.         }  
  112.   
  113.         node.size = size;  
  114.         s_ptrContainer[pResult] = node;  
  115.     }  
  116.     else if (isFree)   
  117.     {  
  118.         ITER  it = s_ptrContainer.find(ptr);  
  119.         if (it != s_ptrContainer.end())  
  120.         {  
  121.             s_ptrContainer.erase(ptr);  
  122.         }  
  123.     }  
  124.       
  125.     MyHookInit();  
  126.   
  127.     return  pResult;  
  128. }  
  129.   
  130. static void MyFreeHook(void* ptr, const void* caller)  
  131. {  
  132.     if (NULL == ptr)  
  133.         return ;  
  134.   
  135.     MyHookUnInit();  
  136.   
  137.     ITER  it = s_ptrContainer.find(ptr);  
  138.     if (it != s_ptrContainer.end())  
  139.     {  
  140.         s_ptrContainer.erase(ptr);  
  141.     }  
  142.   
  143.     ::free(ptr);  
  144.   
  145.     MyHookInit();  
  146. }  
  147.   
  148. static void MyHookInit(void)  
  149. {  
  150.     old_malloc_hook = __malloc_hook;  
  151.     old_realloc_hook = __realloc_hook;  
  152.     old_free_hook = __free_hook;  
  153.   
  154.     __malloc_hook = &MyMallocHook;  
  155.     __realloc_hook = &MyReallocHook;  
  156.     __free_hook = &MyFreeHook;  
  157. }  
  158.   
  159. static void MyHookUnInit(void)  
  160. {  
  161.     __malloc_hook = old_malloc_hook;  
  162.     __realloc_hook = old_realloc_hook;  
  163.     __free_hook   = old_free_hook;  
  164. }  
  165.   
  166.   
  167. ///////////// TEST   
  168. static void  ReportMemoryLeak(void)  
  169. {  
  170.     if (s_ptrContainer.empty())  
  171.     {  
  172.         printf("DEBUG No Memory leak\n");  
  173.         return;  
  174.     }  
  175.   
  176.     ITER  it(s_ptrContainer.begin());  
  177.     while (it != s_ptrContainer.end())  
  178.     {  
  179.         printf("================================================\n");  
  180.         printf("DEBUG Memory leak at %p, size =[%lu]bytes\n", it->first, it->second.size);  
  181.         std::vector<std::string>::const_iterator  stackiter(it->second.stackinfo.begin());  
  182.         std::vector<std::string>::const_iterator  end(it->second.stackinfo.end());  
  183.         int   frameNo = 0;  
  184.         while (stackiter != end)  
  185.         {  
  186.             std::string  mangleName = (*stackiter).c_str();  
  187.             std::size_t start  = mangleName.find('(');  
  188.             std::size_t end    = mangleName.find('+', start);  
  189.             if (std::string::npos == start || std::string::npos == end)  
  190.             {  
  191.                 printf("Frame[%d]: %s\n", frameNo, (*stackiter).c_str());  
  192.             }  
  193.             else  
  194.             {  
  195.                 ++ start;  
  196.                 int status = 0;  
  197.                 char* name = abi::__cxa_demangle(mangleName.substr(start, end - start).c_str(), NULL, 0, &status);  
  198.                 if (0 == status)  
  199.                 {  
  200.                     printf("Frame[%d]: %s\n", frameNo, name);  
  201.                     ::free(name);  
  202.                 }  
  203.                 else  
  204.                 {  
  205.                     printf("Frame[%d]: %s\n", frameNo, (*stackiter).c_str());  
  206.                 }  
  207.             }  
  208.   
  209.             ++ frameNo;  
  210.             ++ stackiter;  
  211.         }  
  212.   
  213.         ++ it;  
  214.     }  
  215. }  




下面是一个测试文件file.cc,编译指令如下

g++ -rdynamic  file.cc linux_vld.o

[cpp] view plaincopyprint?
  1. #include <stdlib.h>     
  2.     
  3. void* TestMalloc()    
  4. {    
  5.     return ::malloc(12);    
  6. }    
  7.     
  8. void* TestRealloc(void* ptr)    
  9. {    
  10.     return ::realloc(ptr, 128);    
  11. }    
  12.     
  13.     
  14. int main(int ac, char* av[])    
  15. {    
  16.     void* ptr = TestMalloc();    
  17.     ::free(ptr);    
  18.     ptr = TestMalloc();    
  19.     ptr = NULL;    
  20.     ptr = TestRealloc(ptr);    
  21. }    


程序退出时输出如下

[html] view plaincopyprint?
  1. ================================================    
  2. DEBUG Memory leak at 0x50c010, size =[12]bytes    
  3. Frame[0]: ./a.out [0x405ee5]    
  4. Frame[1]: TestMalloc()    
  5. Frame[2]: ./a.out(main+0x26) [0x4056fa]    
  6. Frame[3]: /lib64/libc.so.6(__libc_start_main+0xf4) [0x2ab4fc643154]    
  7. Frame[4]: ./a.out(__gxx_personality_v0+0x69) [0x405619]    
  8. ================================================    
  9. DEBUG Memory leak at 0x50c160, size =[128]bytes    
  10. Frame[0]: ./a.out [0x405d09]    
  11. Frame[1]: TestRealloc(void*)    
  12. Frame[2]: ./a.out(main+0x3b) [0x40570f]    
  13. Frame[3]: /lib64/libc.so.6(__libc_start_main+0xf4) [0x2ab4fc643154]    
  14. Frame[4]: ./a.out(__gxx_personality_v0+0x69) [0x405619]  
原创粉丝点击