从希望与梦想构建LLVM Sanitizer
Trail of Bits每年举办为期一个月的冬季实习计划。2019年,我们迎来了4位实习生参与3个项目。本文作者Carson Harmon是普渡大学的新毕业生,专注于编译器和系统工程领域,现已成为我们研究团队的正式成员。
项目初衷
我最初计划在LLVM中实现动态指针分析(points-to analysis)。该技术能够确定程序中指针所指向的内存数据类型及分配位置,对于验证静态分析准确性、增强分析上下文以及追踪对象生命周期具有重要意义。
LLVM Sanitizer基础架构
LLVM Sanitizer框架是实现此类分析的理想平台,它提供:
- 编译时代码插桩能力
- 包含libc实现的运行时支持库
- 函数替换接口
- 内存/线程管理系统
- 操作系统特定系统调用支持
现有广泛使用的检测工具均基于该框架实现,例如:
- AddressSanitizer:检测非法堆栈/堆访问、释放后使用等内存错误
- MemorySanitizer:发现未初始化读取
- LeakSanitizer:定位内存泄漏
- UndefinedBehaviorSanitizer:捕获未定义行为(如整数溢出)
构建自定义Sanitizer的技术路径
由于文档缺乏,我通过以下资源逆向工程LLVM工作机制:
- Eli Bendersky的博客和GitHub仓库
- Adrian Sampson博士的博客
- EuroLLVM会议论文
- LLVM工具链官方文档
核心组件交互关系
-
编译器驱动架构
作为各模块间的粘合剂,负责传递代码生成过程中的所有信息。Sanitizer开发可能需要修改:- 类型生成流程
- Pass调度逻辑
- 运行时库链接机制
![Clang前端、LLVM IR、compiler-rt与驱动的关系图]
-
Pass管理机制
LLVM Pass通过修改IR实现指令插桩。Sanitizer Pass应最后执行以避免被优化Pass影响。驱动根据前端配置注册Pass的执行顺序。 -
运行时组件集成
compiler-rt库支持两种交互方式:- 通过转换Pass插入运行时函数调用
- 使用函数钩子接口劫持目标程序执行
实践指南
我已创建包含以下内容的完整教程:
- 预构建测试Sanitizer示例
- Pass与运行时组件开发分步指南
- LLVM开发实用资源
冬季实习是假期学习的绝佳机会,希望更多企业能开展类似项目。
[Recent Posts内容未翻译]