静态存储区检查
| set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map") set(CMAKE_C_FLAGS "-fdata-sections") set(CMAKE_CXX_FLAGS "-fdata-sections")
|
帮助检测静态存储区的arr数组是否出现了数组越界操作。
动态存储区检查
工具
ASAN
ASAN(Address Sanitizer)是针对 C/C++
的快速内存错误检测工具,在运行时检测 C/C++ 代码中的多种内存错误。 在 GCC
编译选项中设置 -fsanitize=address,启用快速内存错误检测器 ASAN。比如
-fsanitize-coverage=trace-pc,启用覆盖率指导的模糊代码检测,等。
详细参考:Home ·
google/sanitizers Wiki (github.com)
Valgrind
Valgrind由内核(core)以及基于内核的其他调试工具组成。其基于仿真方式对程序进行调试,它先于应用程序获取实际处理器的控制权,并在实际处理器的基础上仿真一个虚拟处理器,并使应用程序运行于这个虚拟处理器之上,从而对应用程序的运行进行监视。
官网
Valgrind工具包包含多个工具,如Memcheck、Cachegrind、Helgrind、Callgrind、Massif。
- Memcheck工具是Valgrind中最常用的工具,用来检测程序中出现的内存问题。
- Callgrind收集程序运行时的一些数据,函数调用关系等信息,还可以有选择地进行cache模拟。在运行结束时,它会把分析数据写入一个文件。
- Helgrind 主要用来检查多线程程序中出现的竞争问题。
- Callgrind 模拟
CPU中的一级缓存I1,D1和L2二级缓存,能够精确地指出程序中
cache的丢失和命中。
- Massif
堆栈分析器,它能测量程序在堆栈中使用了多少内存,如堆块、堆管理块和栈的大小。
简单使用,对下面的 C 程序进行测试:
| #include <stdlib.h> void f(void) { int* x = malloc(10 * sizeof(int)); x[10] = 0; } int main(void) { f(); return 0; }
|
| sudo apt install valgrind
gcc -g valgrind_test.c -o valgrind_test
valgrind --leak-check=yes --tool=memcheck ./valgrind_test
|
自定义带检测的内存管理函数
在实际内容前后加上指定的标记数据,达到检测哨兵的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #define BEFORE_RED_AREA_LEN (4) #define AFTER_RED_AREA_LEN (4) #define LEN_AREA_LEN (4) #define BEFORE_RED_AREA_DATA (0x11223344u) #define AFTER_RED_AREA_DATA (0x55667788u) void *Malloc(size_t __size) { void *ptr = malloc(BEFORE_RED_AREA_LEN + AFTER_RED_AREA_LEN + __size + LEN_AREA_LEN); if (NULL == ptr) { printf("[%s]malloc error\n", __FUNCTION__); return NULL; } *((unsigned int*)(ptr)) = BEFORE_RED_AREA_DATA; *((unsigned int*)(ptr + BEFORE_RED_AREA_LEN)) = __size; *((unsigned int*)(ptr + BEFORE_RED_AREA_LEN + LEN_AREA_LEN + __size)) = AFTER_RED_AREA_DATA; void *data_area_ptr = (ptr + BEFORE_RED_AREA_LEN + LEN_AREA_LEN); return data_area_ptr; }
void CheckMem(void *ptr, size_t __size) { void *data_area_ptr = ptr; printf("[%s]before_red_area_data = 0x%x\n", __FUNCTION__, *((unsigned int*)(data_area_ptr - LEN_AREA_LEN - BEFORE_RED_AREA_LEN))); assert(*((unsigned int*)(data_area_ptr - LEN_AREA_LEN - BEFORE_RED_AREA_LEN)) == BEFORE_RED_AREA_DATA); printf("[%s]len_area_data = 0x%x\n", __FUNCTION__, *((unsigned int*)(data_area_ptr - LEN_AREA_LEN))); assert(*((unsigned int*)(data_area_ptr - LEN_AREA_LEN)) == __size); printf("[%s]after_red_area_data = 0x%x\n", __FUNCTION__, *((unsigned int*)(data_area_ptr + __size))); assert(*((unsigned int*)(data_area_ptr + __size)) == AFTER_RED_AREA_DATA); }
void Free(void *ptr) { void *all_area_ptr = ptr - LEN_AREA_LEN - BEFORE_RED_AREA_LEN; printf("[%s]before_red_area_data = 0x%x\n", __FUNCTION__, *((unsigned int*)(all_area_ptr))); assert(*((unsigned int*)(all_area_ptr)) == BEFORE_RED_AREA_DATA); size_t __size = *((unsigned int*)(all_area_ptr + BEFORE_RED_AREA_LEN)); printf("[%s]before_red_area_data = 0x%x\n", __FUNCTION__, *((unsigned int*)(all_area_ptr + BEFORE_RED_AREA_LEN + LEN_AREA_LEN + __size))); assert(*((unsigned int*)(all_area_ptr + BEFORE_RED_AREA_LEN + LEN_AREA_LEN + __size)) == AFTER_RED_AREA_DATA); free(all_area_ptr); }
|