设计初衷
排错程序是用于检测代码中某些类型的 bug 的工具。通过 运行原理不尽相同,不过清理程序通常(但并不总是)依赖于 这种形式的编译时插桩 bug。 Fuchsia 利用各种消毒剂发现和诊断危险的虫子 通过其他方式难以找到的类别。
排错程序由构建时标志启用。Sanitizer 构建将持续进行 练习了 Fuchsia 的持续集成 (CI) 和提交队列 (CQ),以及 为 Fuchsia C/C++ 和 Rust 开发者提供服务。
开发者通常受益于排错程序,无需任何特殊操作, 而且只有在清理程序检测到错误时才需要留意。 不过,这也存在一些限制。继续阅读,了解什么是消毒程序 以及如何使用它们
支持的排错程序
Fuchsia 目前支持以下排错程序:
- AddressSanitizer (ASan) 可检测 出界访问、在释放 / 返回 / 作用域之后使用以及双重释放。
- LeakSanitizer (LSan) 可检测内存泄漏。 LeakSanitizer 就像一个保守的垃圾回收器,用于检查 是否有泄漏。无法从引用根到达的任何分配 (线程堆栈、线程寄存器、全局变量和 线程局部变量)视为已泄露。
- ThreadSanitizer (TSan) 可检测数据争用(仅主机)。
- UndefinedBehaviorSanitizer (UBSan) 可检测 依赖于未定义程序行为的具体问题。
Zircon 内核中具有以下排错程序行为:
- 物理内存管理器 (PMM) 检查工具 (
pmm_checker
) 可检测 释放后使用 bug 和零散的 DMA。 - Kernel AddressSanitizer (KASan) 将 AddressSanitizer 扩展到内核 与 PMM 协作开发代码。
- Lockdep 是一种运行时锁定验证程序,用于检测锁定危险 例如死锁
默认情况下,会添加以下 C/C++ 编译选项,以检测或 防止在运行时出现错误:
-ftrivial-auto-var-init=pattern
(请参阅 RFC)初始化 自动变量转换为非零模式,以公开与读取相关的 bug 未初始化的内存中- ShadowCallStack 和 SafeStack 可强化 针对堆栈溢出来生成代码。
最后,Fuchsia 使用 libFuzzer, syzkaller,用于执行覆盖率导向型 模糊测试。模糊测试工具与消毒程序的相似之处在于 尝试在运行时发现代码中的错误,这些错误通常用于 连词。模糊测试工具与排错程序的不同之处在于,模糊测试工具会尝试 强制将生产代码执行到可能暴露 bug 的路径中。
支持的配置
目前,本地 build 和 CI/CQ 中支持排错程序 以下配置:
bringup.x64
bringup.arm64
core.x64
core.arm64
zbi_tests.x64
zbi_tests.arm64
此外,排错程序适用于托管工具。
在 qemu 上通过 CI/CQ 进行上述所有测试 和 Intel NUC。其他平台没有使用排错程序进行测试,原因如下: 资源和容量问题,但您可以在本地在这些平台上进行测试 使用下文中的构建工作流程
在 //vendor
下定义的配置的其他 tryjobs 可能会显示在
某些已登录用户的 Gerrit 和 CI 控制台中。查找配置
名称中包含 -asan
。
上面列出的排错程序适用于 C/C++ 代码。此外,LSan 应用于 Rust 代码,用于检测 Rust 内存泄漏。
排查排错程序问题
构建
Fuchsia 平台 build(树内)
如需重现排错程序 build,您可以使用 build 变体来启用排错程序:
fx set product --variant asan-ubsan --variant host_asan-ubsan
或者,您也可以选择仅对某些二进制文件进行插桩:
fx set product --variant asan-ubsan/executable_name
选择性插桩工作流有助于 完全插桩 build 不适合设备的硬件。
具体而言,要检测内核代码中的释放后使用 bug,您需要 启用内核 PMM 检查工具。
树外构建
使用 Fuchsia 工具链进行编译时,只需传递
-fsanitize=
标志,用于指明要使用的排错程序。
请参阅编译器文档。
创建包含插桩组件的 Fuchsia 软件包时,您需要执行以下操作: 请确保您的软件包包含所有运行时依赖项,包括 作为 Clang 工具链的一部分分发的排错程序运行时;以及 插桩 C 库,作为 Fuchsia SDK 的一部分进行分发 sysroot 下。
测试
像往常一样在本地工作流中或在具有
已启用排错程序(tryjob 的名称中包含 asan
)。如果清理程序检测到
系统就会将消息输出到包含
以下字符串:
ERROR: AddressSanitizer
ERROR: LeakSanitizer
SUMMARY: UndefinedBehaviorSanitizer
WARNING: ThreadSanitizer
在这些消息之后,您会看到可表明
找出问题所在并找出根本原因您可以在以下位置找到这些消息:
fx log
。
请注意,触发排错程序的测试可能仍会显示为已通过。 排错程序问题不会表现为测试失败。
排错程序检测到的问题通常具有类似的根本原因。您可能是 通过搜索 Fuchsia 错误来找到以前工作的参考资料 出现了错误。
已知问题
#[should_panic]
Fuchsia 的 Rust 在 panic!
上构建了中止。这与
减小二进制文件的大小。遗憾的是,使用
#[should_panic]
属性可能会错误地检测内存泄漏。这些测试会发出
在预期之内的 panic,然后在未展开的情况下退出,这意味着它们
堆分配。对于 LeakSanitizer 而言,无法辨别
内存不足导致的
如果此问题影响您的测试,您可以在排错程序 build 中停用它,方法是 请参阅此示例。
请参阅:问题 88496:Rust 测试应该触发 leaksanitizer
最佳做法
确保通过测试来演练您的代码
清理程序会在运行时公开错误。除非您的代码在运行,例如在测试中运行 或者一般通过 CI/CQ、排错程序执行的方式在 Fuchsia 上进行 并不能暴露代码中的错误
确保排错程序覆盖率的最佳方法是确保测试 它们的覆盖范围请查阅有关测试的指南 覆盖率。
请勿在代码中抑制排错程序
对于某些构建目标,排错程序可能会抑制。最常见的是 用于排错程序支持推出之前的问题, 针对不属于 Fuchsia 项目的第三方代码中的问题。
被禁排毒程序应被视为技术债务,因为它们不仅隐藏了老化剂, 但会阻止您发现在代码中引入的新 bug。 理想情况下,不应添加新的限制,而应采用现有的抑制 并修复底层错误
您可以通过修改 BUILD.gn
文件来抑制排错程序,该文件定义了
您的可执行目标,如下所示:
executable("please_fix_the_bugs") {
...
# TODO(https://fxbug.dev/42074368): delete the below and fix the memory bug.
deps += [ "//build/config/sanitizers:suppress-asan-stack-use-after-return" ]
# TODO(https://fxbug.dev/42074368): delete the below and fix the memory bug.
deps += [ "//build/config/sanitizers:suppress-asan-container-overflow" ]
# TODO(https://fxbug.dev/42074368): delete the below and fix the memory leak.
deps += [ "//build/config/sanitizers:suppress-lsan.DO-NOT-USE-THIS" ]
}
以上示例展示了如何抑制所有排错程序。不过,您应该在 大多数情况下都会抑制导致故障的排错程序。请跟踪抑制情况 方法是提交 bug 并在评论中引用该 bug,如上文所示。
停用排错程序的另一种常见方法如下所示:
executable("too_slow_when_built_with_asan") {
...
exclude_toolchain_tags = [ "asan" ]
}
上述两个示例都按整个可执行文件的粒度来抑制。 您可以检测 代码。这对于在特定测试中抑制排错程序非常有用 但不是宽泛的范围。例如,特意使用此参数的测试 引入内存错误并测试排错程序运行时本身。
对于 C/C++,请参阅:
对于 Rust,您可以遵循以下模式:
#[cfg(test)]
mod tests {
#[test]
// TODO(https://fxbug.dev/42074368): delete the below and fix the leak
#[cfg_attr(feature = "variant_asan", ignore)]
fn test_that_leaks() {
// ...
}
}
测试不稳定性
如果被测代码的行为 不确定性。例如,内存泄漏可能仅在某些竞态条件下发生, 条件。如果清理程序错误看起来不稳定,请参阅有关测试 CQ 不稳定。
提交优质错误
遇到排错程序问题时,请提交包含所有 问题排查信息
示例:问题 73214:ASAN use-after-scope in blobfs
bug 报告包含:
- 排错程序(在本例中为 ASan)提供的错误。
- 有关如何构建和以便重现错误。
- 随后的调查详情,其中特定代码指针为 所需的资源。
- 引用相关更改,例如,在本例中,为解决 导致错误的根本原因
路线图
正在进行的工作:
- 硬件加速的 AddressSanitizer (hwasan): 显著降低 asan 的内存开销 能够在 RAM 受限的设备上正常运行,并努力缩小测试数据的缺口 依赖于硬件的代码 另请参阅:RFC-0143: Userspace Top-Byte-Ignore。
- GWP-ASan:我们目前正在努力 演示了如何使用此抽样版 asan 来检测 字段。
- 通过系统调用进行覆盖率导向型内核模糊测试。
未来工作领域:
- ThreadSanitizer (TSan):检测数据争用。
- 对检测并发 bug 的内核支持。
- 扩展对 Rust 的排错程序支持,例如检测内存安全 bug
在 Rust
unsafe {}
代码块中或在 FFI 调用之间,或者 来检测未定义的行为 bug。 - MemorySanitizer (MSan):检测 未初始化内存。
另请参阅:2021 年路线图中的排错程序。