开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
摘要
作为C/C++程序员,具有操作内存的能力,但是这也造成C/C++程序员易由于内存操作不当,导致产生各种bug,AddressSanitizer作为一种编译器和运行技术,可用于查找各种bug。
AddressSanitizer作用
AddressSanitizer (ASan) 是一种编译器和运行时技术。最初由 Google 引入,它是运行时错误检查和静态分析的一种强大的替代方法。 它提供运行时 bug 查找技术,这些技术可直接使用现有的生成系统和现有的测试资产。
从 Visual Studio 2019 版本 16.9 开始,Microsoft 的 AddressSanitizer 技术可实现与 Visual Studio IDE 的集成。 如果擦除器在运行时发现 bug,该功能可以选择创建故障转储文件。前提是在运行程序之前设置了 ASAN_SAVE_DUMPS=MyFileName.dmp 环境变量。
AddressSanitizer支持检查的bug
在其说明的文档列出了AddressSanitizer可以在运行期检查出的部分bug,可以看出AddressSanitizer的功能还是很强大的。
- alloc/dealloc 不匹配和 new/delete 类型不匹配
- 分配内存和释放内存的函数不匹配,如new分配内存,delete[] 释放内存
- 构造函数和析构函数不匹配, 子类构造、基类析构
- 分配对堆来说太大
- calloc 溢出和 alloca 溢出
函数原型:void* calloc(unsigned int num,unsigned int size); 功能:在内存的动态存储区中分配num个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。 函数原型:void * __cdecl alloca(size_t); 功能:在调用 alloca的函数返回的时候, 它分配的内存会自动释放。 也就是说, 用 alloca 分配的内存在栈上。 alloca不具可移植性, 而且在没有传统堆栈的机器上很难实现。- 当calloc设定的数量为非法值,如-1
- 当alloca申请的栈空间的索引值大于其空间时,如
char *str = (char *)_alloca(len);//len=10;index=33; str[index] = '1'; // Boom !
- 重复释放和释放后使用
- 重复释放:new申请的内存,被delete两次(首次delete后未将指针置为nullptr)
- 指针被释放后仍操作指针:就是常说的悬挂指针
- 全局变量溢出
- C程序中,指针越界
- 堆缓冲区溢出
- new[]申请内存,但是使用时,索引值越界
- 对齐值对齐无效
void * _aligned_malloc(size_t size,size_t alignment); size:请求的内存分配的大小。 alignment:对齐值,必须是 2 的整数次幂。void* ptr = _aligned_malloc(8,5);//触发该错误 - memcpy 和 strncat 参数重叠(自测VS2022未检查出该问题)
- 堆栈缓冲区溢出和下溢
- 溢出:定义数组,而后索引越界
- 下溢:索引值为-1
- return 后使用堆栈和限定作用域后使用
此检查需要通过额外的编译器选项 /fsanitize-address-use-after-return 并通过设置环境变量 ASAN_OPTIONS=detect_stack_use_after_return=1 激活的代码生成。- 操作已经析构的局部变量
- 在内存中毒后使用内存
AddressSanitizer的安装
在安装VS2019时可以选择安装该工具,如果VS2019已经安装完成但未安装该功能,可以通过控制面板找到VS2019,然后右键->更改,勾选C++ AddressSanitizer,然后单击安装(或更改)即可。具体的选择界面如下:
AddressSanitizer用法
介绍以VS IDE开启AddressSanitizer,步骤如下:
- 选中项目->右键->属性,打开属性页
- 选中C/C++ -> 常规 ->启用地址擦除器系统
- 如果安装VS2022或更高版本的VS时,还可以启用模糊支持
开启AddressSanitizer后重新编译工程,F5调试执行即可
AddressSanitizer案例
源代码如下,用以分配对堆来讲太大
char* buffer = (char*)malloc(x * y * x * y); //Boom!
memcpy(buffer, buffer + 8, 8);
允许时AddressSanitizer给出的反馈如下: