关于 address-sanitizer
AddressSanitizer(ASan)是一种编译期插桩的内存错误检测技术,适用于软件测试和模糊测试。它提供运行时诊断,可发现越界访问、释放后使用等问题。
主要功能
- 01编译期插桩内存操作
- 02检测缓冲区溢出与释放后使用
- 03报告内存分配和调用栈信息
- 04通过 ASAN_OPTIONS 配置行为
- 05可与多种模糊测试器集成
适用场景
- 01排查 C/C++ 程序的内存错误
- 02测试含 unsafe 代码的 Rust 项目
- 03在单元测试中定位内存破坏
- 04分析模糊测试发现的崩溃
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trailofbits/ skills --skill address-sanitizer安装后在 Claude Code 中输入/address-sanitizer确认已加载。
附带文件agents/openai.yamlassets/trail-of-bits-mark.svg
详细介绍
AddressSanitizer(ASan)
AddressSanitizer(ASan)是一种广泛采用的内存错误检测工具,在软件测试中,尤其是模糊测试中被大量使用。它有助于检测可能被忽略的内存损坏漏洞,例如缓冲区溢出、释放后使用错误以及其他内存安全违规。
概述
ASan 能有效识别内存漏洞,因此已成为模糊测试中的标准做法。它会在编译时对代码进行插桩,以跟踪内存分配和访问,并在运行时检测非法操作。
核心概念
| 概念 | 描述 |
|---|---|
| 插桩 | ASan 会在编译期间为内存操作添加运行时检查 |
| 影子内存 | 映射 20 TB 虚拟内存,以跟踪分配状态 |
| 性能开销 | 与未插桩的代码相比,速度约降低 2–4 倍 |
| 检测范围 | 可发现缓冲区溢出、释放后使用错误、重复释放和内存泄漏 |
适用场景
在以下场景中应用此技术:
- 对 C/C++ 代码进行模糊测试,以查找内存安全漏洞
- 使用 unsafe 块测试 Rust 代码
- 调试与内存损坏有关的崩溃
- 在怀疑存在内存错误时运行单元测试
在以下场景中跳过此技术:
- 运行生产代码(ASan 可能会降低安全性)
- 平台为 Windows 或 macOS(ASan 支持有限)
- 对于你的用例,性能开销无法接受
- 对不涉及 FFI 的纯安全语言进行模糊测试(例如纯 Go、纯 Java)
快速参考
| 任务 | 命令/模式 |
|---|---|
| 启用 ASan(Clang/GCC) | -fsanitize=address |
| 启用详细输出 | ASAN_OPTIONS=verbosity=1 |
| 禁用泄漏检测 | ASAN_OPTIONS=detect_leaks=0 |
| 出错时强制中止 | ASAN_OPTIONS=abort_on_error=1 |
| 多个选项 | ASAN_OPTIONS=verbosity=1:abort_on_error=1 |
分步指南
第 1 步:使用 ASan 编译
使用 -fsanitize=address 标志编译并链接代码:
clang -fsanitize=address -g -o my_program my_program.c
建议使用 -g 标志,以便 ASan 检测到错误时提供更清晰的堆栈跟踪。
第 2 步:配置 ASan 选项
设置 ASAN_OPTIONS 环境变量以配置 ASan 的行为:
export ASAN_OPTIONS=verbosity=1:abort_on_error=1:detect_leaks=0
第 3 步:运行程序
执行经过 ASan 插桩的二进制文件。检测到内存错误时,ASan 会输出详细报告:
./my_program
第 4 步:调整模糊测试器的内存限制
ASan 需要约 20 TB 虚拟内存。请禁用模糊测试器的内存限制:
- libFuzzer:
-rss_limit_mb=0 - AFL++:
-m none
常见模式
模式:基本 ASan 集成
使用场景: 标准模糊测试设置,启用 ASan
之前:
clang -o fuzz_target fuzz_target.c
./fuzz_target
之后:
clang -fsanitize=address -g -o fuzz_target fuzz_target.c
ASAN_OPTIONS=verbosity=1:abort_on_error=1 ./fuzz_target
模式:ASan 与单元测试
使用场景: 为单元测试套件启用 ASan
之前:
gcc -o test_suite test_suite.c -lcheck
./test_suite
之后:
gcc -fsanitize=address -g -o test_suite test_suite.c -lcheck
ASAN_OPTIONS=detect_leaks=1 ./test_suite
高级用法
提示与技巧
| 提示 | 作用 |
|---|---|
使用 -g 标志 | 提供详细的堆栈跟踪,便于调试 |
设置 verbosity=1 | 确认 ASan 在程序启动前已启用 |
| 在模糊测试期间禁用泄漏检测 | 泄漏检测不会立即导致崩溃,还会使输出变得杂乱 |
启用 abort_on_error=1 | 某些模糊测试器需要使用 abort() 而不是 _exit() |
理解 ASan 报告
ASan 检测到内存错误时,会输出详细报告,其中包括:
- 错误类型:缓冲区溢出、释放后使用错误等
- 堆栈跟踪:错误发生的位置
- 分配/释放跟踪:内存分配/释放的位置
- 内存映射:错误周围的影子内存状态
ASan 报告示例:
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000eff4 at pc 0x00000048e6a3
READ of size 4 at 0x60300000eff4 thread T0
#0 0x48e6a2 in main /path/to/file.c:42
组合使用 Sanitizer
ASan 可以与其他 Sanitizer 组合使用,以实现全面检测:
clang -fsanitize=address,undefined -g -o fuzz_target fuzz_target.c
平台注意事项
Linux:全面支持 ASan,性能最佳 macOS:支持有限,部分功能可能无法使用 Windows:支持处于实验阶段,不建议用于生产环境的模糊测试
反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
| 在生产环境中使用 ASan | 可能降低应用程序的安全性 | 仅在测试时使用 ASan |
| 未禁用内存限制 | 模糊测试器可能因 20TB 虚拟内存而终止进程 | 设置 -rss_limit_mb=0 或 -m none |
| 忽略泄漏报告 | 内存泄漏表明资源管理存在问题 | 在模糊测试活动结束时查看泄漏报告 |
工具专属指南
libFuzzer
同时使用模糊测试器和地址消毒器进行编译:
clang++ -fsanitize=fuzzer,address -g harness.cc -o fuzz
运行时不限制 RSS:
./fuzz -rss_limit_mb=0
集成提示:
- 始终将
-fsanitize=fuzzer与-fsanitize=address结合使用 - 使用
-g在崩溃报告中生成详细的堆栈跟踪 - 考虑使用
ASAN_OPTIONS=abort_on_error=1,以更好地处理崩溃
AFL++
使用 AFL_USE_ASAN 环境变量:
AFL_USE_ASAN=1 afl-clang-fast++ -g harness.cc -o fuzz
运行时不限制内存:
afl-fuzz -m none -i input_dir -o output_dir ./fuzz
集成提示:
AFL_USE_ASAN=1会自动添加适当的编译标志- 使用
-m none禁用 AFL++ 的内存限制 - 对于覆盖率映射较大的程序,可考虑使用
AFL_MAP_SIZE
cargo-fuzz(Rust)
使用 --sanitizer=address 标志:
cargo fuzz run fuzz_target --sanitizer=address
或在 fuzz/Cargo.toml 中配置:
[profile.release]
opt-level = 3
debug = true
集成提示:
- ASan 适用于对不安全 Rust 代码或 FFI 边界进行模糊测试
- 安全 Rust 代码可能无法从中获得同等程度的收益(编译器已能阻止许多错误)
- 重点关注不安全代码块、原始指针和 C 库绑定
参见:cargo-fuzz:AddressSanitizer
honggfuzz
使用 ASan 编译并与 honggfuzz 链接:
honggfuzz -i input_dir -o output_dir -- ./fuzz_target_asan
编译目标:
hfuzz-clang -fsanitize=address -g target.c -o fuzz_target_asan
集成提示:
- honggfuzz 开箱即可与 ASan 良好配合
- 使用反馈驱动模式,以便在启用消毒器时获得更好的覆盖率
- 监控内存用量,因为 ASan 会增加内存占用
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 模糊测试器立即终止进程 | 内存限制太低,无法满足 ASan 的 20TB 虚拟内存需求 | 使用 -rss_limit_mb=0(libFuzzer)或 -m none(AFL++) |
| “ASan runtime not initialized” | 链接顺序错误或缺少运行时 | 确保编译和链接时都使用 -fsanitize=address |
| 泄漏报告使输出杂乱 | 默认启用了 LeakSanitizer | 设置 ASAN_OPTIONS=detect_leaks=0 |
| 性能较差(减速超过 4 倍) | 处于调试模式或构建未优化 | 使用 -O2 或 -O3 与 -fsanitize=address 一起编译 |
| ASan 未检测到明显错误 | 二进制文件未插桩 | 使用 ASAN_OPTIONS=verbosity=1 检查 ASan 是否打印了启动信息 |
| 误报 | 拦截器冲突 | 查看 ASan 常见问题解答,了解特定库的已知问题 |
相关技能
使用此技术的工具
| 技能 | 应用方式 |
|---|---|
| libfuzzer | 使用 -fsanitize=fuzzer,address 编译,以集成模糊测试和内存错误检测 |
| aflpp | 在编译期间使用 AFL_USE_ASAN=1 环境变量 |
| cargo-fuzz | 使用 --sanitizer=address 标志,为 Rust 模糊测试目标启用 ASan |
| honggfuzz | 使用 -fsanitize=address 编译目标,进行 ASan 插桩模糊测试 |
相关技术
| 技能 | 关联 |
|---|---|
| undefined-behavior-sanitizer | 常与 ASan 结合使用,以全面检测错误(未定义行为和内存错误) |
| fuzz-harness-writing | 测试框架必须能够处理 ASan 检测到的崩溃并避免误报 |
| coverage-analysis | 覆盖率引导的模糊测试有助于触发 ASan 可检测内存错误的代码路径 |
资源
关键外部资源
AddressSanitizer on Google Sanitizers Wiki
官方 ASan 文档涵盖:
- 算法与实现细节
- 可检测错误类型的完整列表
- 性能特征与开销
- 平台特定行为
- 已知限制与不兼容性
所有 Sanitizer 共用的通用配置标志:
verbosity:控制诊断输出级别log_path:将 Sanitizer 输出重定向到文件symbolize:在报告中启用/禁用符号解析external_symbolizer_path:使用自定义符号化器
ASan 专用配置选项:
detect_leaks:控制内存泄漏检测abort_on_error:出错时调用abort()还是_exit()detect_stack_use_after_return:检测栈上的 use-after-return 缺陷check_initialization_order:查找初始化顺序缺陷
常见陷阱与解决方案:
- 链接顺序问题
- 与其他工具的冲突
- 平台特定问题
- 性能调优技巧
Clang AddressSanitizer Documentation
Clang 专属指南:
- 编译标志与选项
- 与其他 Clang 特性的交互
- 支持的平台与架构
GCC 专属 ASan 文档:
- GCC 专属标志与行为
- 与 Clang 实现的差异
- GCC 中的平台支持
AddressSanitizer: A Fast Address Sanity Checker (USENIX Paper)
包含技术细节的原始研究论文:
- 影子内存算法
- 虚拟内存需求(历史上为 16TB,现在约 20TB)
- 性能基准测试
- 设计决策与权衡