前言
作为c的程序员,最常见的就是排查内存泄漏,如果没有被内存泄漏折磨过,说明你写的程序太简单了。本篇文章是本人最近几天突发奇想写的一个小工具,其中参考了大量资料,遇到各种奇葩问题,最后翻墙一一解决,因此决定写个博客总结一下。
说明:下面代码中涉及大量c语言高级知识和linux环境下劫持的知识,仔细研究相信会收获很大,
环境:
第一步、
测试代码:
先来个简单的分配释放内存例子
helloworld.c
#include <stdio.h> #include <stdlib.h> void fun(void) { void *p = malloc(10); //分配内存 free(p); //释放内存 } int main(void) { fun(); return 0; }
第二步、
劫持代码:
hack_malloc.c
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> static void *(*mymalloc)(size_t) = NULL; static void (*myfree)(void *) = NULL; static void __attribute__((constructor)) init(void) { mymalloc = dlsym(RTLD_NEXT, "malloc"); myfree = dlsym(RTLD_NEXT, "free"); if (!mymalloc) { fprintf(stderr, "unable to get malloc symbol!\n"); exit(1); } if (!myfree) { fprintf(stderr, "unable to get free symbol!\n"); exit(1); } fprintf(stderr, "libhack_malloc.so successfully wrapped!\n"); } void *malloc(size_t size) { const void *caller_addr = __builtin_return_address(0); fprintf(stderr, "malloc_addr %p size=%lu\n", caller_addr - 1, size); return mymalloc(size); } void free(void *ptr) { const void *caller_addr = __builtin_return_address(0); fprintf(stderr, "free_addr %p\n", caller_addr - 1); myfree(ptr); }
知识点一、
__attribute__((constructor))的作用 参考:https://blog.csdn.net/sun172270102/article/details/88227519
知识点二、
1、gcc默认不支持__builtin_return_address(LEVEL)的参数为非0。好像只支持参数为0。
2、__builtin_return_address(0)的含义是,得到当前函数返回地址,即此函数被别的函数调用,然后此函数执行完毕后,返回,所谓返回地址就是那时候的地址。
3、__builtin_return_address(1)的含义是,得到当前函数的调用者的返回地址。注意是调用者的返回地址,而不是函数起始地址。
知识点三、
dlsym(RTLD_NEXT, "malloc"); 的作用参考:https://blog.csdn.net/Cxinsect/article/details/100761916
注意点:
1、#define _GNU_SOURCE 不能省略
2、只能使用fprintf 不能使用printf,因为printf内部会调用malloc导致死循环
第三步、
测试脚本:
gcc hack_malloc.c -o libhack_malloc.so -fPIC -shared -ldl -g3 gcc helloworld.c -o helloworld -g3 -no-pie export LD_PRELOAD=/root/damo/libhack_malloc.so ./helloworld export LD_PRELOAD=
注意点:
1、-no-pie不能省略
2、LD_PRELOAD= 最后尽量还原一下,以免造成意外错误
运行结果:
记住地址 0x400548和0x400558,下面会转换
第四步、
addr2line工具用法参考:https://www.jianshu.com/p/c2e2b8f8ea0d
地址转换命令:addr2line -f -e 可执行程序 -a 地址
可以看到0x400548对应malloc、0x400558对应free了,行号、文件、函数信息都已经解析出来了。这些信息都已经拿到了,是不是就可以排查内存是否泄漏了呢?后续我准备使用python脚本或者shell脚本解析,敬请期待......
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复