C语言编程中比较麻烦的就是内存问题,泄露,越界等,而且不好测试。如果是在嵌入式环境下,就更麻烦了,不好单步调试。这里作者笔记一个脚本,可以方便的测试出内存泄露。
CONTENTS
函数替换
首先根据自己的环境,替换下内存申请和释放函数
#if 1 typedef unsigned int MEM_UINT; #define MEM_LOG printf #define MEM_TEST_INT 0xABCDEF90 #define Malloc(SIZE_M) \ ({ \ int SIZE = SIZE_M; \ char *tmp = malloc(sizeof(MEM_UINT) + SIZE + sizeof(MEM_UINT)); \ *((MEM_UINT *)tmp) = (MEM_UINT)SIZE; \ *((MEM_UINT *)(tmp + SIZE + sizeof(MEM_UINT))) = MEM_TEST_INT; \ MEM_LOG("MEM_Malloc %x @%s:%d\r\n", (MEM_UINT)tmp, __FILE__,__LINE__);\ (tmp + sizeof(MEM_UINT));\ }) #define Free(POINT_M) \ {\ char *POINT = POINT_M;\ if(POINT == NULL) \ {MEM_LOG("MEM_Free_NULL @%s:%d \r\n", __FILE__,__LINE__);} \ else \ { \ char *tmp = POINT - sizeof(MEM_UINT); \ MEM_UINT size = *((MEM_UINT *)tmp); \ MEM_UINT test_int = *((MEM_UINT *)(POINT + size)); \ if(test_int != MEM_TEST_INT) \ { \ MEM_LOG("MEM_Over_Write %x %x-%x @%s:%d ", (MEM_UINT)tmp, test_int, MEM_TEST_INT, __FILE__,__LINE__);\ }else \ { \ MEM_LOG("MEM_Free %x @%s:%d ", (MEM_UINT)tmp, __FILE__,__LINE__);\ } \ free(tmp); \ MEM_LOG("SUCCESS\r\n");\ } \ } #else #define Malloc malloc #define Free free #endif
Demo代码和输出
main.c
int main(int argc, char *argv[]) { char *pTest1 = Malloc(2); char *pTest2 = Malloc(3); char *pTest3 = Malloc(4); char *pTest4 = Malloc(5); Free(NULL); Free(pTest1); Free(pTest2); Free(pTest3); char *pTest = Malloc(10); pTest[10] = 3; Free(pTest); return 0; }
输出
MEM_Malloc ba469010 @../MemLeakTest/main.c:51 MEM_Malloc ba469440 @../MemLeakTest/main.c:52 MEM_Malloc ba469460 @../MemLeakTest/main.c:53 MEM_Malloc ba469480 @../MemLeakTest/main.c:54 MEM_Free_NULL @../MemLeakTest/main.c:56 MEM_Free ba469010 @../MemLeakTest/main.c:57 SUCCESS MEM_Free ba469440 @../MemLeakTest/main.c:58 SUCCESS MEM_Free ba469460 @../MemLeakTest/main.c:59 SUCCESS MEM_Malloc ba469460 @../MemLeakTest/main.c:61 MEM_Over_Write ba469460 abcdef03-abcdef90 @../MemLeakTest/main.c:63 SUCCESS
内存分析
首先讲下面这份python代码保存,比如保存为MemAnalysis.py
#!/usr/bin/python3 # -*- coding: UTF-8 -*- malloc_dict = dict(); free_null_list = list(); over_write_list = list(); def handle_malloc_line(line_buf): buf_arr = line_buf.split(" "); if(buf_arr[1] in malloc_dict): print( "Addr:%d Malloced Before %s %s\r\n"%(buf_arr[1], malloc_dict[ buf_arr[1] ], line_buf)); else: malloc_dict[ buf_arr[1] ] = line_buf; return; def handle_free_line(line_buf): buf_arr = line_buf.split(" "); if(buf_arr[1] in malloc_dict): del malloc_dict[buf_arr[1]]; else: print( "Release MEM not Malloced %s"%(line_buf) ); return; def handle_free_null_line(line_buf): buf_arr = line_buf.split(" "); free_null_list.append( buf_arr[1] ); return; def handle_over_write_line(line_buf): handle_free_line(line_buf); over_write_list.append(line_buf); return; def finish_log_handle(): print("Free NULL:"); for free_null in free_null_list: print(free_null); print("Over Write:"); for over_write in over_write_list: print(over_write); mem_leak_keys = malloc_dict.keys(); print("Mem Leak:"); for mem_leak in mem_leak_keys: print(malloc_dict[mem_leak]); return; analysis_dict = { "MEM_Malloc":handle_malloc_line, "MEM_Free":handle_free_line, "MEM_Free_NULL":handle_free_null_line, "MEM_Over_Write":handle_over_write_line }; log_file = open("mem_test.log", "r"); while True: line_buf = log_file.readline(); if not line_buf: break; parse_key_list = analysis_dict.keys(); for parse_key in parse_key_list: start_with_parse_key = line_buf.startswith(parse_key); if(start_with_parse_key == True): parse_func = analysis_dict[parse_key]; parse_func(line_buf); break; else: continue; log_file.close(); finish_log_handle();
讲日志保存为mem_test.log,和python脚本放到同一目录下,然后执行命令:
$ python3 MemAnalysis.py Free NULL: @../MemLeakTest/main.c:56 Over Write: MEM_Over_Write ba469460 abcdef03-abcdef90 @../MemLeakTest/main.c:63 SUCCESS Mem Leak: MEM_Malloc ba469480 @../MemLeakTest/main.c:54
可以看到,内存泄露也越界都别识别出来了。
发表评论