地址 sanitizer 内部原理

这是一篇关于 AddressSanitizer(ASan)的文章,主要内容如下:

  • 前提条件:需要具备基本的 C 语言知识(内存、栈、堆、系统调用),可选 x86_64 汇编知识。
  • 前言:Xavier Login 是新入职的实习生,被要求编写一个程序通过验证魔法字节是否设置来验证输入。他最初的代码存在栈缓冲区溢出错误,修改后再次编译执行却没有任何反应,引发了他的疑惑,而本文将帮助他理解 ASan 如何工作。
  • AddressSanitizer 介绍:ASan 是用于 C 和 C++的内存误用检测器工具,包含编译时的插装模块和运行时库。现代多数 C/C++编译器都支持 ASan,如 GNU GCC(4.8 及以上)、Clang LLVM(3.1 及以上)、MSVC(16.4 及以上)。
  • 错误类型:ASan 可检测 C/C++中的多种内存错误,包括全局缓冲区下溢/上溢、栈缓冲区下溢/上溢、堆缓冲区下溢/上溢、初始化顺序错误、返回后使用、作用域后使用、释放后使用、内存泄漏等。
  • 核心概念

    • 内存映射:将程序的虚拟地址空间分为应用内存(约 7/8)、阴影内存(约 1/8)和保护内存,用于检测对阴影内存的非法访问。
    • 阴影内存:用于存储应用内存中数据的元数据,通过MemToShadow函数将应用内存地址映射到阴影内存地址,每个阴影内存字节对应应用内存的 8 字节,通过分析阴影内存的位可以检测内存错误。
    • 感染:在malloc()调用时对应用内存中的某些字节进行“中毒”处理,并在阴影内存中存储中毒字节的信息,以便检测内存错误。
  • 插装模块:目标是在每个内存指令前添加运行时检查,初始化时添加__asan_init_vN()调用,对loadstore指令进行增强,以添加内存检查,同时也对栈上的变量进行插装。
  • 运行时库:定义了插装部分所需的所有函数,包括阴影和应用地址映射、内存相关函数的拦截、栈的处理和错误报告等。
  • 错误报告:分析 ASan 出错时的输出,包括错误类型、操作类型、回溯、地址、内存视图和阴影字节说明等部分,帮助程序员定位内存错误。
  • 性能:ASan 会占用约 1/8 的虚拟内存,使代码平均慢 1.93 倍,相比 Valgrind 性能较好。
  • 结论:ASan 是检测内存误用的强大工具,对性能影响较小,易于在构建环境中启用,能为程序员提供很多帮助。

引用的参考文献:Github: Sanitizers WikiClang: AddressSanitizer DocumentationAddressSanitizerAlgorithmAddressSanitizer: A Fast Address Sanity CheckerFinding races and memory errors with LLVM instrumentationGCC Asan Module Instrumentation

阅读 18
0 条评论