Android 支持多种内存错误调试工具。每种工具都有其优缺点,请阅读下文以决定哪种工具最适合你的用例。本文档概述了可用的工具,以便你决定进一步研究哪种工具,但本文力求简洁,因此请阅读工具特定的文档以获取详细信息。
内容摘要
- 只要可能,就使用内存安全语言,以完全避免内存错误
- 始终使用 PAC/BTI 来缓解 ROP/JOP 攻击
- 始终使用 GWP-ASan 来检测生产环境中罕见的内存错误
- 在测试期间使用 HWASan 检测内存错误
- 支持 MTE 的设备通常不可用。在这种情况改变之前,这将不会有所帮助
- 仅在别无选择时才在测试期间使用 ASan
内存安全语言
内存安全语言是完全避免和缓解内存错误的唯一方法。此页面上的其他工具可以帮助你使内存不安全的代码更安全、更可靠,但使用内存安全语言可以消除整类问题。
Android 官方支持的内存安全语言是 Java 和 Kotlin。大多数 Android 应用使用其中一种语言开发会更容易。
话虽如此,确实有一些应用开发者交付了用 Rust 编写的代码,如果你正在阅读本页,你可能有充分的理由需要原生代码(可移植性、性能,或两者兼有)。Rust 是在 Android 上编写内存安全的原生代码的最佳选择。如果你选择这条路,NDK 团队不一定能帮助你解决遇到的问题,但我们很乐意听取相关反馈!
PAC/BTI
指针认证和分支目标识别,也称为 PAC/BTI,是适合在生产环境中使用的一种缓解工具。尽管是独立的技术,但它们由相同的编译器标志控制,因此始终一起使用。
这些功能与不支持它们的设备向后兼容,因为使用的新指令在早期设备上是空操作。此外,还需要足够新的内核和足够新的操作系统版本。在 /proc/cpuinfo
中查找 paca
和 bti
可以显示你是否拥有足够新的硬件和内核。Android 12(API 31)具备必要的用户空间支持。
优点
- 可在所有 build 中启用,不会在旧设备或内核上造成问题(但请确保你已在确实支持它的设备/内核/操作系统组合上进行过实际测试!)
缺点
- 仅适用于 64 位应用
- 无法缓解不支持此功能的设备上的错误
- 1% 的代码大小开销
GWP-Asan
GWP-ASan 可用于检测现场的内存错误,但采样率过低,无法作为一种有效的缓解措施。
优点
- 无明显的 CPU 或内存开销
- 部署简单:无需重新构建原生代码
- 适用于 32 位应用
缺点
- 低采样率需要大量用户才能有效发现 bug
- 仅检测堆错误,不检测栈错误
HWASan
硬件地址清理程序,也称为 HWASan,是测试期间捕获内存错误的最佳工具。与自动化测试结合使用时最有用,尤其是在运行模糊测试时,但根据应用的性能需求,它也可能在高端手机的内部测试环境中使用。
优点
- 无误报
- 检测 ASan 无法检测到的其他类别的错误(返回后使用栈)
- 漏报率低于 MTE(1/256 vs 1/16)
- 内存开销低于 ASan(最接近的替代工具)
缺点
- 显著的 CPU (~100%)、代码大小 (~50%) 和内存 (10% - 35%) 开销
- 在 API 34 和 NDK r26 之前,需要刷写兼容 HWASan 的镜像
- 仅适用于 64 位应用
MTE
内存标签扩展,也称为 MTE,是 HWASan 的一种低成本替代方案。除了调试和测试功能外,它还可用于检测和缓解生产环境中的内存损坏问题。如果你有用于测试 MTE build 的硬件,则应启用此功能。
优点
- 开销足够低,许多应用可以在生产环境中容忍
- 无误报
- 检测堆错误不需要重新构建代码(但检测栈错误需要)
缺点
- 截至 2024 年,没有默认启用 MTE 的商用设备,但 Arm 的文档解释了如何在 Pixel 8/Pixel 8 Pro 上启用 MTE 进行测试。
- 漏报率为 1/16,而 HWASan 为 1/256
- 仅适用于 64 位应用
- 需要为同时支持 MTE 和不支持 MTE 的设备构建单独的库
ASan
地址清理程序,也称为 ASan,是可用工具中最老、最广泛可用的。它在测试期间捕获内存错误以及调试仅影响旧设备(其中没有其他可用工具)的问题时非常有用。只要可能,请优先使用 HWASan。
优点
- 广泛可用。可能适用于像 KitKat 一样旧的设备
- 正确使用时没有误报或漏报
缺点
- 难以正确构建和打包
- 所有选项中开销最高:~100% CPU、~50% 代码大小、~100% 内存使用
- 不再受支持
- 存在已知 bug,且不会修复