• 内存泄漏检测组件的实现


    1. 通过宏定义来包装 mallocfree 函数,以便在每次内存分配和释放时记录相关信息,如文件名和行号。这使得你能够跟踪哪个函数在哪里分配和释放内存。

    1. #define _GNU_SOURCE
    2. #include <dlfcn.h>
    3. #include <stdio.h>
    4. #include <stdlib.h>
    5. #include <unistd.h>
    6. #include <link.h>
    7. // 方式一:宏定义
    8. void *_malloc(size_t size, char *filename,int line) {
    9. void *ptr = malloc(size);
    10. char file[128] = {0};
    11. sprintf(file ,"./mem/%p.mem" ,ptr);
    12. FILE *fp = fopen(file ,"w");//w小写
    13. fprintf(fp, "[+]addr: %p filename: %s line: %d\n",ptr,filename,line);
    14. fflush(fp);
    15. fclose(fp);
    16. return ptr;
    17. }
    18. void _free(void *ptr, char *filename,int line) {
    19. char file[128] = {0};
    20. sprintf(file,"./mem/%p.mem",ptr);
    21. if(unlink(file) < 0){//unlink用于在文件系统中删除指定的文件
    22. printf("double free %p\n",ptr);
    23. return;
    24. }
    25. return free(ptr);
    26. }
    27. // __FILE__ 获取文件名
    28. // __LINE__ 获取函数执行的行号
    29. #define malloc(size) _malloc(size, __FILE__,__LINE__)
    30. #define free(ptr) _free(ptr, __FILE__,__LINE__)
    31. int main(void) {
    32. init_hook();
    33. void *p1 = malloc(8);
    34. void *p2 = malloc(16);
    35. void *p3 = malloc(32);
    36. free(p1);
    37. free(p2);
    38. return 0;
    39. }

    编译执行: 

     表示在memleak.c 文件中, 第149行出现内存泄漏问题。

    2.通过使用hook方法来重定向 mallocfree 函数, 与此同时通过__builtin_return_address()函数的返回值结合(*caller) 命令: addr2line -f -e ./程序名 -a 返回值(caller) 查看内存泄露的程序及具体行数。

    1. #define _GNU_SOURCE
    2. #include <dlfcn.h>
    3. #include <stdio.h>
    4. #include <stdlib.h>
    5. #include <unistd.h>
    6. #include <link.h>
    7. //方式二:hook
    8. // gcc -o memleak memleak.c -g -ldl
    9. // addr2line -f -e ./memleak -a 0x400b38(返回值)
    10. typedef void *(*malloc_t)(size_t size);
    11. malloc_t malloc_f = NULL;
    12. typedef void (*free_t)(void *ptr);
    13. free_t free_f = NULL;
    14. int enable_malloc_hook = 1;
    15. int enable_free_hook = 1;
    16. void *COnvertToELF(void *addr) {
    17. Dl_info info;
    18. struct link_map *link;
    19. dladdr1(addr, &info, (void**)&link,RTLD_DL_LINKMAP);
    20. return (void*)((size_t)addr - link->l_addr);
    21. }
    22. void *malloc(size_t size) {
    23. void *ptr = NULL;
    24. if (enable_malloc_hook) {
    25. enable_malloc_hook = 0;
    26. ptr = malloc_f(size);
    27. // main --> f1() --> f2() --> f3() { __builtin_return_address(0) }
    28. void *caller = __builtin_return_address(0);
    29. char filename[128] = {0};
    30. sprintf(filename, "./mem/%p.mem", ptr);
    31. FILE *fp = fopen(filename, "w");
    32. fprintf(fp, "[+] caller: %p, addr: %p, size: %ld\n",
    33. COnvertToELF(caller), ptr, size);
    34. fflush(fp);
    35. enable_malloc_hook = 1;
    36. } else {
    37. ptr = malloc_f(size);
    38. }
    39. return ptr;
    40. }
    41. void free(void *ptr) {
    42. if (enable_free_hook) {
    43. enable_free_hook = 0;
    44. char file[128] = {0};
    45. sprintf(file, "./mem/%p.mem", ptr);
    46. if (unlink(file) < 0) { // filename no exist;
    47. printf("double free: %p\n", ptr);
    48. return ;
    49. }
    50. free_f(ptr);
    51. enable_free_hook = 1;
    52. } else {
    53. free_f(ptr);
    54. }
    55. }
    56. void init_hook(void) {
    57. if (!malloc_f) {
    58. malloc_f = dlsym(RTLD_NEXT, "malloc");
    59. }
    60. if (!free_f) {
    61. free_f = dlsym(RTLD_NEXT, "free");
    62. }
    63. }
    64. int main(void) {
    65. init_hook();
    66. void *p1 = malloc(8);
    67. void *p2 = malloc(16);
    68. void *p3 = malloc(32);
    69. free(p1);
    70. free(p2);
    71. return 0;
    72. }

    编译执行:

     表示在memleak.c 文件的 main 函数中, 第149行出现内存泄漏问题。

    源文件 memleak.c 

    1. #define _GNU_SOURCE
    2. #include <dlfcn.h>
    3. #include <stdio.h>
    4. #include <stdlib.h>
    5. #include <unistd.h>
    6. #include <link.h>
    7. // 方式一:宏定义
    8. #if 0
    9. void *_malloc(size_t size, char *filename,int line) {
    10. void *ptr = malloc(size);
    11. char file[128] = {0};
    12. sprintf(file ,"./mem/%p.mem" ,ptr);
    13. FILE *fp = fopen(file ,"w");//w小写
    14. fprintf(fp, "[+]addr: %p filename: %s line: %d\n",ptr,filename,line);
    15. fflush(fp);
    16. fclose(fp);
    17. return ptr;
    18. }
    19. void _free(void *ptr, char *filename,int line) {
    20. char file[128] = {0};
    21. sprintf(file,"./mem/%p.mem",ptr);
    22. if(unlink(file) < 0){//unlink用于在文件系统中删除指定的文件
    23. printf("double free %p\n",ptr);
    24. return;
    25. }
    26. return free(ptr);
    27. }
    28. // __FILE__ 获取文件名
    29. // __LINE__ 获取函数执行的行号
    30. #define malloc(size) _malloc(size, __FILE__,__LINE__)
    31. #define free(ptr) _free(ptr, __FILE__,__LINE__)
    32. //方式二:hook
    33. #elif 1
    34. // gcc -o memleak memleak.c -g -ldl
    35. // addr2line -f -e ./memleak -a 0x400b38
    36. typedef void *(*malloc_t)(size_t size);
    37. malloc_t malloc_f = NULL;
    38. typedef void (*free_t)(void *ptr);
    39. free_t free_f = NULL;
    40. int enable_malloc_hook = 1;
    41. int enable_free_hook = 1;
    42. void *COnvertToELF(void *addr) {
    43. Dl_info info;
    44. struct link_map *link;
    45. dladdr1(addr, &info, (void**)&link,RTLD_DL_LINKMAP);
    46. return (void*)((size_t)addr - link->l_addr);
    47. }
    48. void *malloc(size_t size) {
    49. void *ptr = NULL;
    50. if (enable_malloc_hook) {
    51. enable_malloc_hook = 0;
    52. ptr = malloc_f(size);
    53. // main --> f1() --> f2() --> f3() { __builtin_return_address(0) }
    54. void *caller = __builtin_return_address(0);
    55. char filename[128] = {0};
    56. sprintf(filename, "./mem/%p.mem", ptr);
    57. FILE *fp = fopen(filename, "w");
    58. fprintf(fp, "[+] caller: %p, addr: %p, size: %ld\n",
    59. COnvertToELF(caller), ptr, size);
    60. fflush(fp);
    61. enable_malloc_hook = 1;
    62. } else {
    63. ptr = malloc_f(size);
    64. }
    65. return ptr;
    66. }
    67. void free(void *ptr) {
    68. if (enable_free_hook) {
    69. enable_free_hook = 0;
    70. char file[128] = {0};
    71. sprintf(file, "./mem/%p.mem", ptr);
    72. if (unlink(file) < 0) { // filename no exist;
    73. printf("double free: %p\n", ptr);
    74. return ;
    75. }
    76. free_f(ptr);
    77. enable_free_hook = 1;
    78. } else {
    79. free_f(ptr);
    80. }
    81. }
    82. void init_hook(void) {
    83. if (!malloc_f) {
    84. malloc_f = dlsym(RTLD_NEXT, "malloc");
    85. }
    86. if (!free_f) {
    87. free_f = dlsym(RTLD_NEXT, "free");
    88. }
    89. }
    90. #endif
    91. #if 1
    92. int main(void) {
    93. init_hook();
    94. void *p1 = malloc(8);
    95. void *p2 = malloc(16);
    96. void *p3 = malloc(32);
    97. free(p1);
    98. free(p2);
    99. return 0;
    100. }
    101. #endif

    注意:提前在程序目录下创建mem文件夹,编译时添加 -g -ldl

    具体使用时只需将该文件的main函数注释掉,与需要检测的程序源文件一起编译执行即可。 

  • 相关阅读:
    php内核基础说明
    32篇年度最佳AI论文;Python编译器Codon开源;ChatGPT的前世今生
    PyTorch概述(四)---DataLoader
    CSDN博客运营团队2022年H1总结
    多数元素(Java版)
    pytest框架中的pytest.ini配置文件
    机器视觉工程师成功三大法宝:正确的方向,不断的努力,合理的安排时间
    计算机科学速成课
    笔记-pandas读取mysql数据
    小红书运营:商家如何选择小红书博主?选择小红书博主需要注意什么?
  • 原文地址:https://blog.csdn.net/m0_68678128/article/details/133829321