关于 sanitizers
为 Agent 提供编译器运行时 Sanitizer 的选择、启用与报告解读指南,涵盖内存错误、未定义行为、数据竞争和内存泄漏,并介绍构建及 CI 配置。
主要功能
- 01按缺陷类型选择 Sanitizer
- 02编译选项与运行时配置
- 03解读检测报告
- 04抑制规则与 CMake 集成
- 05CI 示例及专用 Sanitizer
适用场景
- 01为内存缺陷选择检测工具
- 02分析 ASan 或 UBSan 报告
- 03在 CI 中加入 Sanitizer 检查
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill sanitizers安装后在 Claude Code 中输入/sanitizers确认已加载。
附带文件references/flags.mdreferences/reports.md
详细介绍
Sanitizer(检测器)
用途
指导 Agent 选择、启用和解读编译器运行时 Sanitizer,以查找内存错误、未定义行为、数据竞争和内存泄漏。
触发条件
- “我的程序有内存错误,该用哪种 Sanitizer?”
- “如何启用 ASan?”
- “如何解读 ASan/UBSan/TSan 报告?”
- “ASan 报告 heap-buffer-overflow 是什么意思?”
- “如何屏蔽 Sanitizer 的误报?”
- “可以在 CI 中使用 Sanitizer 吗?”
工作流
1. 决策树:使用哪种 Sanitizer?
Bug class?
├── Memory OOB, use-after-free, double-free → AddressSanitizer (ASan)
├── Stack OOB, global OOB → ASan (all three covered)
├── Uninitialised reads → MemorySanitizer (MSan, Clang only, requires all-clang build)
├── Undefined behaviour (int overflow, null deref, bad cast) → UBSan
├── Data races (multi-thread) → ThreadSanitizer (TSan)
├── Memory leaks only → LeakSanitizer (LSan, standalone or via ASan)
└── Multiple classes → ASan + UBSan (common combo); cannot combine with TSan or MSan
2. AddressSanitizer(ASan)
# GCC or Clang
gcc -fsanitize=address -fno-omit-frame-pointer -g -O1 -o prog main.c
# Or
clang -fsanitize=address -fno-omit-frame-pointer -g -O1 -o prog main.c
运行时选项(通过 ASAN_OPTIONS 设置):
ASAN_OPTIONS=detect_leaks=1:abort_on_error=1:log_path=/tmp/asan.log ./prog
ASAN_OPTIONS 键 | 效果 |
|---|---|
detect_leaks=0/1 | 启用 LeakSanitizer(Linux 上默认为 1) |
abort_on_error=1 | 调用 abort() 而不是 _exit()(用于生成 core dump) |
log_path=path | 将报告写入文件 |
symbolize=1 | 符号化地址(需要将 llvm-symbolizer 放入 PATH) |
fast_unwind_on_malloc=0 | 提供更准确的调用栈(速度较慢) |
quarantine_size_mb=256 | 延迟重新使用已释放的内存 |
解读 ASan 输出:
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000050
READ of size 4 at 0x602000000050 thread T0
#0 0x401234 in foo /home/user/src/main.c:15
#1 0x401567 in main /home/user/src/main.c:42
0x602000000050 is located 0 bytes after a 40-byte region
[0x602000000028, 0x602000000050) allocated at:
#0 0x7f12345 in malloc ...
#1 0x401234 in main /home/user/src/main.c:10
解读:WRITE/READ 中最上方的帧是访问位置;allocated at 调用栈显示分配位置。区域大小为 40 字节,范围是 [start, end),访问发生在 end,即越过末尾一个字节(典型的差一错误)。
3. UndefinedBehaviorSanitizer(UBSan)
gcc -fsanitize=undefined -g -O1 -o prog main.c
# More complete: add specific checks
gcc -fsanitize=undefined,integer -g -O1 -o prog main.c
常见的 UBSan 检查:
signed-integer-overflowunsigned-integer-overflow(默认不包含在undefined中)null— 空指针解引用bounds— 数组索引越界(边界在编译时可确定)alignment— 未对齐的指针访问float-cast-overflow— 浮点数转整数时溢出vptr— C++ 虚表类型不匹配shift-exponent— 移位量 >= 位宽
# Enable everything including integer overflow
gcc -fsanitize=undefined \
-fsanitize=signed-integer-overflow,unsigned-integer-overflow,float-cast-overflow \
-fno-sanitize-recover=all \ # abort instead of continue
-g -O1 -o prog main.c
-fno-sanitize-recover=all:让 UBSan 在首次出错时中止(对 CI 很重要)。
解读 UBSan 输出:
src/main.c:15:12: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
4. ThreadSanitizer(TSan)
# Clang or GCC (GCC ≥ 4.8)
clang -fsanitize=thread -g -O1 -o prog main.c
# TSan is incompatible with ASan and MSan
解读 TSan 输出:
WARNING: ThreadSanitizer: data race (pid=12345)
Write of size 4 at 0x7f... by thread T2:
#0 increment /home/user/src/counter.c:8
Previous read of size 4 at 0x7f... by thread T1:
#0 read_counter /home/user/src/counter.c:3
5. MemorySanitizer(MSan)
MSan 可检测对未初始化内存的读取。仅限 Clang。要求整个构建都启用插桩(不能混用启用 MSan 和未启用 MSan 的对象)。
clang -fsanitize=memory -fno-omit-frame-pointer -g -O1 -o prog main.c
# With origin tracking (slower but shows where uninit value came from)
clang -fsanitize=memory -fsanitize-memory-track-origins=2 -g -O1 -o prog main.c
系统库必须使用 MSan 重新构建,或替换为启用 MSan 插桩的封装库。使用 LLVM 的 msan-libs 工具链。
6. ASan + UBSan 组合使用
gcc -fsanitize=address,undefined -fno-sanitize-recover=all \
-fno-omit-frame-pointer -g -O1 -o prog main.c
不要与 TSan 或 MSan 组合使用。
7. 屏蔽规则
# ASan suppression file
cat > asan.supp << 'EOF'
# Suppress leaks from OpenSSL init
leak:CRYPTO_malloc
EOF
LSAN_OPTIONS=suppressions=asan.supp ./prog
# UBSan suppression
cat > ubsan.supp << 'EOF'
signed-integer-overflow:third_party/fast_math.c
EOF
UBSAN_OPTIONS=suppressions=ubsan.supp:print_stacktrace=1 ./prog
8. CMake 集成
option(SANITIZE "Enable sanitizers" OFF)
if(SANITIZE)
set(san_flags -fsanitize=address,undefined -fno-sanitize-recover=all
-fno-omit-frame-pointer -g -O1)
add_compile_options(${san_flags})
add_link_options(${san_flags})
endif()
9. CI 集成
# GitHub Actions example
- name: Build with ASan+UBSan
run: |
cmake -S . -B build -DSANITIZE=ON
cmake --build build -j$(nproc)
- name: Run tests under sanitizers
run: |
ASAN_OPTIONS=abort_on_error=1:detect_leaks=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
ctest --test-dir build -j$(nproc) --output-on-failure
10. HWASan(硬件辅助 AddressSanitizer)
在支持 TBI(忽略最高字节)或 MTE 的 ARM64 硬件上,其开销低于 ASan。
# Clang/LLVM HWASan (userspace)
clang -fsanitize=hwaddress -g -O1 -o app app.c
# Requires ARM64 with TBI (most Android/arm64 servers) or HWASan tagging support
# Cannot combine with ASan on same build
| Sanitizer | 开销 | 平台 |
|---|---|---|
| ASan | ~2x | x86、arm64 |
| HWASan | ~1.2–1.5x | 支持 TBI/MTE 的 arm64 |
| MSan | ~3x | 仅限 LLVM |
11. MemTagSanitizer(ARM MTE)
使用 ARM 内存标记扩展硬件标记,保障堆、栈和内存安全。
# Experimental — LLVM with MTE-capable hardware (arm64)
clang -fsanitize=memtag -g -O1 -o app app.c
# Kernel MTE (separate from userspace MemTagSanitizer)
# CONFIG_ARM64_MTE=y — hardware tagging in kernel allocator
12. GWP-ASan(生产环境采样)
基于采样和保护页的 ASan,适用于生产环境(Android 已在使用;上游 glibc 集成仍在进行中)。
# LLVM GWP-ASan (link-time, sampled allocations)
clang -fsanitize=gwp-asan -O2 -o app app.c
# Android: enabled in some system components for sampled crash detection
# glibc: experimental GWP-ASan allocator integration (check distro release notes)
以近乎为零的稳态开销,概率性捕获堆越界(OOB)和释放后使用(UAF)。
13. 内核模块的 KASAN
# Build test kernel with KASAN
# CONFIG_KASAN=y CONFIG_KASAN_INLINE=y or CONFIG_KASAN_OUTLINE=y
# Boot KASAN kernel in QEMU for module development
qemu-system-x86_64 -kernel bzImage -append "kasan=on" ...
# Load module — KASAN reports appear in dmesg
sudo insmod mymod.ko
dmesg | tail -30
结合 skills/kernel/kernel-testing,在 KASAN 下运行 KUnit 测试。有关 KASAN 报告的分诊,请参阅 skills/security/kernel-security。
如需快速查阅编译标志,请参阅 references/flags.md。 如需查看报告解读示例,请参阅 references/reports.md。
相关技能
- ASan 不可用时,使用
skills/profilers/valgrind运行 Memcheck - 使用
skills/runtimes/fuzzing自动生成可触发 Sanitizer 错误的输入 - 使用
skills/compilers/gcc或skills/compilers/clang了解构建标志