C++内存错误检测利器--AddressSanitizer
一、概述 1、常见内存问题场景 野指针: 指针未初始化就使用(非法的随机值)、指针越界非法访问,或指向一个已释放的对象等。 内存泄露: 申请的堆内存使用完毕后忘记释放,内存还占着,但地址丢失,自己已经不能控制这块内存,而系统也不能再次将它分配给需要的程序。内存泄漏次数多了就会导致内存溢出。 内存溢出: Out Of Memory,简称OOM,指系统已经不能再分配出你所需要的空间。 内存踩踏: 指访问了不合法的地址(访问了不属于自己的地址),如果访问的地址是其他变量的地址并进行了修改,就会破坏别人的数据,从而导致程序运行异常。常发生在buffer overflow,野指针操作,write after free等场景。 2、常见内存检测工具 在AddressSanitizer出现之前,市面上就已经存在了许多内存检测器,例如: Dr.Memory:检测未初始化的内存访问、double free、use after free 等错误 Mudflap:检测指针的解引用,静态插桩 Insure++:检测内存泄漏 Valgrind:可以检测非常多的内存错误 其中,Dr.Memory、Insure++ 和 Mudflap 虽然在运行时造成的额外损耗比较少,但是检测场景有限;Valgrind 虽然能够在许多场景的检测出错误,但是它实现了自己的一套 ISA 并在其之上运行目标程序,因此它会严重拖慢目标程序的速度。而 AddressSanitizer 在设计时就综合考虑了检测场景、速度的影响因素,结合了 Mudflap 的静态插桩、Valgrind 的多场景检测能力,故本文主要讲解AddressSanitizer。 3、什么是AddressSanitizer AddressSanitizer即地址消毒技术,简称ASan,是一个快速的内存错误检测工具。它可以用来检测内存问题,例如缓冲区溢出或对悬空指针的非法访问等。 检测类型: Use after free(dangling pointer dereference): 释放后使用(堆上分配的空间free之后被再次使用)。 Heap buffer overflow: 堆缓冲区溢出(访问的区域在堆上, 且超过了分配的空间)。 Stack buffer overflow: 栈缓冲区溢出(访问的区域在栈上, 且超过了分配给它的空间)。 Global buffer overflow: 全局缓冲区溢出(访问的区域是全局变量, 且超过了分配给它的空间)。 Use after return: Return后使用(函数在栈上的局部变量在函数返回后被使用默认不开启)。 Use after scope: 在作用域外使用(局部变量离开作用域以后继续使用)。 Initialization order bugs: 初始化顺序错误(检查全局变量或静态变量初始化的时候有没有利用未初始化的变量,默认不开启)。 Memory leaks: 内存泄漏(未释放堆上分配的内存)。 据谷歌的工程师介绍 ,ASan 已在 chromium 项目上检测出了300多个潜在的未知bug,而且在使用 ASan 作为内存错误检测工具对程序性能损耗也是及其可观的。根据检测结果显示可能导致性能降低2倍左右,比Valgrind(官方给的数据大概是降低10-50倍)快了一个数量级。而且相比于Valgrind只能检查到堆内存的越界访问和悬空指针的访问,ASan 不仅可以检测到堆内存的越界和悬空指针的访问,还能检测到栈和全局对象的越界访问。这也是 ASan 在众多内存检测工具的比较上出类拔萃的重要原因,基本上现在 C/C++ 项目都会使用ASan来保证产品质量,尤其是大项目中更为需要。...