单页网站快速收录,wordpress 后台攻击,昆明网站建设论坛,wordpress 模版 摄影一、c/c中的内存问题
memory corruption#xff0c;内存崩溃或者说内存损坏。在c/c程序中#xff0c;有相当一部分的Bug是由内存引起的#xff0c;也就是刚刚提到的内存崩溃。说得再通俗一些#xff0c;往往和内存的非法访问有关。内存问题#xff0c;轻则导致程序失能中的内存问题
memory corruption内存崩溃或者说内存损坏。在c/c程序中有相当一部分的Bug是由内存引起的也就是刚刚提到的内存崩溃。说得再通俗一些往往和内存的非法访问有关。内存问题轻则导致程序失能中则导致程序崩溃重则引起系统瘫痪。 因此在c/c编程的过程中对内存的管理要求非常严格。但灵活多变的指针往往又让很多开发者无法安全的进行内存的处理即使在新的C标准中使用了智能指针或者说自行进行了RAII的封装仍然有可能造成指针引起的内存错误。当然并不是说c/c中指针是内存问题的万恶之源其它情况如数组越界访问等均可以出现类似的问题。 基于上面的内存的问题很多针对内存进行控制的相关工具也有很多。其中有静态内存检查工具Cppcheck等和动态内存检查工具valgrind等。本文介绍一个动态内在检查工具GAS。
二、GAS
GASgoogle address sanitizer也称为ASan它是google公司开发的一个快速的内在检测工具。相比于Valgrind对程序的影响ASan的速度那相当快了。要想监测内存最好的办法是什么当然是替换掉编译器的相关内存管理接口了。ASan就提供了一个插桩模块编译器检测模块LLVM pass和一个提供malloc等函数替代接口的运行时库。 ASan早期就与LLVM3.1进行了结合将其插桩模块整合到了Clang项目中。后来在Gcc4.8中也整合了GAS的相关模块但其配合不太完善所以推荐使用Gcc4.9以上版本。ASan还有一个专门提供给内核使用的版本KASAN有兴趣可以搞一下。
三、基本原理
ASan使用的内存检测机制是使用影子内存shadow memory来记录当前内存是否可以安全访问的方式。其通过影子内存与常规内存normal memory进行映射以期安全的管理内存。通过代码插桩来检查程序运行时影子内存的状态。 当编译器运行时其通过替代的分配内存管理接口在内存分配和回收后的区域进行“投毒”(poisoned)形成所谓的有毒区域如果有visual studio系列的反汇编的经验会很容易理解这段话其实就是对内存进行二次标记管理并设置相关的安全管理区域这个其它的动态内存管理如数组安全检测的机理基本类似。关于影子内存映射的机理和相关细节请查阅谷歌相关论文此处不再赘述。
四、ASan支持的内存检查
ASan对常见的内存问题都进行了支持主要包括下面几点 1、Use after free 这个比较好理解它主要是指堆Heap内存在释放后又被重新使用。这是一种非常常见的内存问题类似于下面的代码
A *a new A();
delete a;
a-pid 0;2、Heap buffer overflow 这也是一种比较常见的内存错误即堆内存溢出也就是越界
char * p new char[10];
p[11] 2;
3、Stack buffer overflow 说过了堆溢出怎么能不提栈溢出呢这个就不举例子了太简单多见了。 4、Global buffer overflow 全局缓冲区溢出这都和堆溢出类似。 5、Use after return 返回值使用无效内存典型的就是返回一个临时变量的指针或引用看下面的代码
int * getData(){int tmp[10];return tmp;
}
int * d getData();6、Use after scope 使用作用域外的内存空间和上面的有些类似。看下面的代码
for(int i 0;i 10;i){}
int p i;7、Initialization order bugs 初始化顺序不同引用的问题这个比较符合C的特性。这个在前面的分析过好多次最典型的就是库中的全局变量与调用者之间调用之间的顺序问题静态变量也有这种可能的现象。 8、Memory leaks 内存泄露这可是写c/c程序员的“亲亲”。不管多么高深的开发者几乎都会遇到这个问题。但有一句话需要说明内存泄露不可怕可怕是内存泄露的累积。
五、应用
在基本了解了ASan后下面举一个例子来进行实践一把。使用ASan的主要步骤分为
1、编写测试程序
#include iostream
#include stdio.h
#include stdlib.h
#include string.hint heapOver() {char *pBuf (char *)malloc(10 * sizeof(char));memcpy(pBuf 10, abcd1234, 8);free(pBuf);return 0;
}
int *getData() {int *arr new int[10];delete arr;return arr;
}
int main() {heapOver();int arr[10] {0};int d arr[11];int *p getData();delete p;return 0;
}2、在编译时增加相关参数 gcc中增加-fsanitizeaddress选项如果想获得较好性能建议增加-O1或更高编译优化选项;增加fno-omit-frame-pointer选项可以提供更友好的堆栈回溯信息
3、编译并运行
#编译:注意如果不加-g选项则无法准确的显示出问题的源码位置可自行测试一下不带-g
~/project/ASanTest$ g -fsanitizeaddress -fno-omit-frame-pointer -g -o asanTest main.cpp
#运行
~/project/ASanTest$ ./asanTest 94673ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001a at pc 0x7f6acbe3a2c3 bp 0x7ffde51ff060 sp 0x7ffde51fe808
WRITE of size 8 at 0x60200000001a thread T0#0 0x7f6acbe3a2c2 in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827#1 0x55b7993f9381 in heapOver() /home/qt65_project/ASanTest/main.cpp:8#2 0x55b7993f9477 in main /home/fqt65_project/ASanTest/main.cpp:19#3 0x7f6acb629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58#4 0x7f6acb629e3f in __libc_start_main_impl ../csu/libc-start.c:392#5 0x55b7993f9284 in _start (/home//qt65_project/ASanTest/asanTest0x1284)0x60200000001a is located 0 bytes to the right of 10-byte region [0x602000000010,0x60200000001a)
allocated by thread T0 here:#0 0x7f6acbeb4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145#1 0x55b7993f935e in heapOver() /home/qt65_project/ASanTest/main.cpp:7#2 0x55b7993f9477 in main /home/fqt65_project/ASanTest/main.cpp:19#3 0x7f6acb629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
Shadow bytes around the buggy address:0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa 00[02]fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):Addressable: 00Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: faFreed heap region: fdStack left redzone: f1Stack mid redzone: f2Stack right redzone: f3Stack after return: f5Stack use after scope: f8Global redzone: f9Global init order: f6Poisoned by user: f7Container overflow: fcArray cookie: acIntra object redzone: bbASan internal: feLeft alloca redzone: caRight alloca redzone: cbShadow gap: cc
94673ABORTING
大家可以依次的进行测试就会将三种类型的问题都在运行时暴露出来。分别报得错误是“堆溢出、栈溢出和分配释放不匹配”。而且描述的非常详细和准确大家可以自己动手实践一把。
六、总结
工欲善其事必先利其器。不是常说某某是编程界的瑞士军刀么。其实只要是刀用好了都会起到事半功倍的效果。要想写出好的代码除了有思想上的指导在实践中熟练的应用各种开发工具也是必不可少的。
、