踩内存问题一键定位:HWASAN + BinXO无源码内存检测实战指南

0 评论 152 浏览 0 收藏 19 分钟

   HWASAN(Hardware-Assisted Address Sanitizer,硬件辅助地址消毒器)是 Clang 开源社区推出的一种内存检测工具,主要用于开发态的内存问题检测。它利用 ARMv8.5 及以上芯片的 MTE(Memory Tagging Extension)硬件特性,在内存访问时通过 tag 比对快速发现踩内存问题。

本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:

踩内存问题一键定位:HWASAN + BinXO无源码内存检测实战指南-华为开发者话题 | 华为开发者联盟

 

适用版本:DevEco Studio 6.1.0.830 及以上版本

【背景与收益】

什么是 HWASAN?

HWASAN(Hardware-Assisted Address Sanitizer,硬件辅助地址消毒器)是 Clang 开源社区推出的一种内存检测工具,主要用于开发态的内存问题检测。它利用 ARMv8.5 及以上芯片的 MTE(Memory Tagging Extension)硬件特性,在内存访问时通过 tag 比对快速发现踩内存问题。

注意:HWASAN 定位为开发态检测工具,不建议在发布版本中使能。其主要用于开发阶段和测试阶段快速发现内存问题,提升应用稳定性。

在鸿蒙应用开发中,踩内存(Memory Corruption 是 C++ Native 层最常见的稳定性问题之一。踩内存问题包括堆缓冲区溢出(heap-buffer-overflow)、堆内存释放后使用(heap-use-after-free)、双重释放(double-free)等,这些问题往往导致应用随机崩溃,且由于崩溃现场与根因脱节,定位极其困难。

为什么需要 HWASAN + BinXO?

       传统 HWASAN(Hardware-Assisted Address Sanitizer)需要开发者基于源码重新编译,面临以下痛点:

痛点 说明
跨部门沟通成本高 应用内部模块多,二进制文件.so 散落在各部门,需要所有库重新编译
四方库无法插桩 第三方动态库无源码,传统 HWASAN 无法检测
定位效率低 未插桩模块踩内存导致随机崩溃,根因无法关联

HWASAN + BinXO 方案的核心收益

       • ✅ 无源码插桩:基于 BinXO 二进制编译优化技术,对已编译的 .so 动态库直接进行 HWASAN 插桩,无需源码

       • ✅ 一键使能DevEco Studio 6.1.0.830+ 版本支持 IDE 界面勾选,无需手动添加编译参数

       • ✅ 全面覆盖:同时开启源码编译插桩 + 无源码二进制插桩,检测覆盖率大幅提升

       • ✅ 快速定位IDE 集成堆栈跟踪分析工具,直接定位报错和申请

 

【技术原理】

BinXO 二进制插桩原理

BinXO 是华为自研的轻量化二进制编译优化器,可以在二进制层级进行优化和运行时信息采集。基于 BinXO 的 SourceLess HWASAN 方案,在汇编层级对已编译的 .so 动态库进行 HWASAN 插桩,实现无源码场景下的内存访问检测。

 核心流程如下:

       1. 访存指令插桩:在汇编层级识别所有 load/store 访存指令,插入 tag 检查逻辑

          • 保存部分寄存器于上,用于后续计算

          • 提取访问地址 addr

          • 计算对应 tag(基于地址高位 / shadow memory

          • 与 shadow memory 中存储的 tag 对比

          • 不匹配则触发异常(report + abort),匹配则恢复相关寄存器继续运行

       2. 堆内存插桩:识别 malloc/free 函数的调用点,动态插入 tag 分配和回收代码

          • 分配内存时自动添加 tag

          • 释放内存时自动清除 tag 信息

          • 为返回地址高位打上 tag

       3. 运行时检测:每次内存访问时,检查地址高位 tag  shadow memory 中的 tag 是否一致,不匹配则触发异常

支持检测的内存问题类型

问题类型 源码编译插桩 BinXO 二进制插桩
heap-buffer-overflow(堆缓冲区溢出)
heap-use-after-free(堆释放后使用)
double-free(双重释放)
alloc-size-too-big(分配过大)
out-of-memory(内存不足)
stack-buffer-overflow(栈缓冲区溢出)
global-overflow(全局变量溢出)

注意:BinXO 二进制插桩当前主要支持堆类内存检测,栈类检测需使用源码编译插桩。

可检测的访存指令类型

BinXO 支持以下访存指令的检测:

标量指令

          • A64_LDP_STP

             A64_LDR_STR_IMMED

             A64_LDR_STR_REG

             A64_LDR_STR_UNSIGNED_IMMED

SIMD 指令

          • A64_LDX_STX_MULTIPLE

          • A64_LDX_STX_MULTIPLE_POST

          • A64_LDX_STX_SINGLE

          • A64_LDX_STX_SINGLE_POST

【典型使用场景】

       以下场景推荐使用 HWASAN + BinXO 进行内存问题检测:

       1C++ Native 占比高的应用:如音视频处理、游戏引擎、图像处理等大量使用 C++ 的应用

       2集成第三方 SDK 的应用:第三方 SDK 通常只有编译好的 .so 文件,无源码可用

       3线上踩内存问题频发:天网版本检测到大量踩内存问题,需要快速定位根因

       4跨模块内存问题排查:多个模块间内存交互复杂,需要全量插桩检测

       未使用 HWASAN + BinXO 时,开发者可能遇到以下问题:

问题现象 影响
应用随机崩溃,日志无法定位根因 崩溃现场与踩内存根因脱节,排查困难
第三方 SDK 踩内存无法检测 无源码场景下传统 HWASAN 无法插桩
跨模块内存问题定位周期长 以某应用为例,未插桩模块踩内存攻关一个月才定位
小概率问题为结论处理比例高 踩内存导致随机崩溃,领域投入分析积极性低

【详细操作指南】

方式:IDE 界面配置(推荐)

适用场景:调试/本地场景,DevEco Studio 6.1.0.830 及以上版本

       步骤 1:创建 Native 工程

       在 DevEco Studio 中创建包含 C++ Native 的代码工程。

       步骤 2:开启 HWASAN

       1. 点击菜单 Run > Edit Configurations

       2. 进入 Diagnostics 选项卡

       3. 勾选 Hardware-Assisted Address Sanitizer,开启 C++ 源码编译插桩检测

       步骤 3:开启 BinXO(无源码二进制插桩)

       从 DevEco Studio 6.1.0.830 版本开始,在同一界面勾选 BinXO check,开启无源码 .so 文件的 HWASAN 插桩检测。

       步骤 4:构建 HAP 包

       点击构建按钮,DevEco Studio 将自动完成 HWASAN 源码插桩和 BinXO 二进制插桩,生成检测包。

       步骤 5:推包并运行测试

       1. 将构建的 HAP 包推送到设备

       2. 关闭应用 freeze 检测(依赖 HAP 包指定为 DEBUG 包):

aa attach -b <bundleName>

       3. 启动应用,执行相关用例

       步骤 6:获取 HWASAN 日志

       IDE 将自动收集 HWASAN 日志,可在日志视图中查看。

       步骤 7:堆栈跟踪分析

       1. 将 HWASAN 日志拷贝到 IDE 分析工具的左上角区域

       2. 勾选 解读堆栈跟踪

       3. 导入符号表信息

       4. 点击 开始分析

       5. 观测右下角的 报错  申请,直接定位问题

 

方式二:配置文件

适用场景:需要持久化配置或流水线构建

       系统级配置

       在工程目录下的 AppScope/app.json5 文件中添加 HWASAN 配置开关:

{
  "app": {
    "hwasanEnabled": true
  }
}

       模块级配置

       在模块级 build-profile.json5 中添加构建参数:

{
  "buildOption": {
    "externalNativeOptions": {
      "arguments": [
        "-DOHOS_ENABLE_HWASAN=ON",
        "-DOHOS_ENABLE_BINXO=ON"
      ]
    }
  }
}

版本说明

• DevEco Studio 6.1.0.830 以下版本:仅配置 -DOHOS_ENABLE_HWASAN=ON(仅源码插桩)

• DevEco Studio 6.1.0.830 及以上版本:同时配置两个参数,开启源码 + 无源码检测

 

方式三:命令行参数

适用场景:流水线/CI 构建

# DevEco Studio 6.1.0.830 及以上版本
hvigorw assembleHar -p ohos-enable-hwasan=true -p ohos-enable-binxo=true

# DevEco Studio 6.1.0.830 以下版本(仅源码插桩)
hvigorw assembleHar -p ohos-enable-hwasan=true

       可选配置:排除特定 SO

       部分 .so 由于技术原理限制不支持 BinXO 插桩,需要配置忽略以避免构建报错:

{
  "buildOption": {
    "nativeLib": {
      "excludeSoFromBinXO": ["**/liblibrary.so"]
    }
  }
}

支持正则匹配,可在工程级或模块级 build-profile.json5 中配置。

【真实案例分析】

XXXX App 案例

       XXXX App 使用 SourceLess HWASAN 后,帮助开发者发现了 libxxxa.so 中的访存问题。

原始日志:

Reason:HWASAN
==appspawn==14177==ERROR: HWAddressSanitizer: allocation-tail-overwritten; heap object [0x00130004a600,0x00130004aa51) of size 1105

Stack of invalid access unknown. Issue detected at deallocation time.
deallocated here:
#0 0x5ae366b394 (/system/asan/lib64/libclang_rt.hwasan.so+0x2b394) (BuildId: ace54fff777e92f7758544f77b2b931f9f1c7b55)
#1 0x651af0b720 (/data/storage/el1/bundle/libs/arm64/libtocks.so+0xb720) (BuildId: 85c301da032d17f70c0e1d6bf4de932b58317447)
#2 0x5aee4e6c84 (/system/asan/lib64/platformsdk/libace_napi.z.so+0x66c84) (BuildId: ccd61d3dec598e77f88de9fb142e4095)
#3 0x7e86a5b5cc (/system/asan/lib64/module/arkcompiler/stub.an+0x5c85cc)
#4 0x7e864a3320 (/system/asan/lib64/module/arkcompiler/stub.an+0x10320)
#5 0x275bdd79f4 ([anon:ArkTS Heapsemi space]+0x179f4)

allocated here:
#0 0x5ae366b0e0 (/system/asan/lib64/libclang_rt.hwasan.so+0x2b0e0) (BuildId: ace54fff777e92f7758544f77b2b931f9f1c7b55)
#1 0x651af12d54 (/data/storage/el1/bundle/libs/arm64/libtocks.so+0x12d54) (BuildId: 85c301da032d17f70c0e1d6bf4de932b58317447)
#2 0x651af0b6b0 (/data/storage/el1/bundle/libs/arm64/libtocks.so+0xb6b0) (BuildId: 85c301da032d17f70c0e1d6bf4de932b58317447)
#3 0x5aee4e6c84 (/system/asan/lib64/platformsdk/libace_napi.z.so+0x66c84) (BuildId: ccd61d3dec598e77f88de9fb142e4095)
#4 0x7e86a5b5cc (/system/asan/lib64/module/arkcompiler/stub.an+0x5c85cc)
#5 0x7e864a3320 (/system/asan/lib64/module/arkcompiler/stub.an+0x10320)
#6 0x275bdd79f4 ([anon:ArkTS Heapsemi space]+0x179f4)

从日志可以看出,堆内存[0x00130004a600,0x00130004aa51) 出现了越界访问。该块内存的申请的代码在libtocks.so+0x12d54的位置。

反汇编该so,通过汇编可以看出,在0x12d6c的位置有一个越界访问。 如果开发者有源码, 可以更快的发现内存的问题。

检测效果

          • 无需获取第三方库源码

          • 直接定位到具体 .so 文件中的问题

          • 大幅缩短问题定位周期

【常见问题解答】

Q1:BinXO 二进制插桩有哪些规格限制?

限制项 规格
ELF 文件大小 ≤ 128MB
目标文件类型 C/C++ 编译的 .so 动态库
二进制体积增加 约 2 倍
内存占用增加 10% ~ 35%
性能影响 在源码编译插桩基础上增加 1.5x ~ 3x

Q2:HWASAN 使用 ARM64 地址高 8 位,会与应用冲突吗?

HWASAN 使用了 ARM64 虚拟地址的高 8 位作为 tag 存储。如果应用中也有动态库使用了高 8 位,会产生冲突导致误报。

规避方案

       1. 优先方案:该动态库针对 HWASAN 版本单独出一个二进制,关闭对地址高 8 位的使用

       2. 次选方案:关闭该 .so  HWASAN/BinXO 插桩(影响:该 .so 的踩内存故障无法检测

Q3:源码编译插桩遇到 `fixup not sufficiently aligned` 报错怎么办?

根因:HWASAN 源码编译要求栈变量 16 字节对齐,报错文件中有内联汇编开辟了未 16 字节对齐的栈变量,或定义了 pack 强制未 16 字节对齐的临时变量。

解决方案

          • 修改为 16 字节对齐

          • 或在问题函数定义右侧添加修饰符__attribute__((no_sanitize(“hwaddress“)))该函数不进行 HWASAN 编译插桩

Q4:BinXO 插桩报错如何处理?

错误码 错误描述 处理建议
0x11801001 输入文件已经是支持 HWASAN 的文件 跳过该文件
0x11801002 输入文件大小超过规格限制 跳过该文件或拆分减小文件大小
0x11801003 输入文件损坏或缺少相关 ELF 信息 跳过该文件
0x11801004 输入文件不是 C/C++ 编译而来 跳过该文件
0x11801007 输入文件不是标准 ELF 文件 跳过该文件
0x11801009 输入或输出文件无法打开 提供正确的文件名或路径
0x1180100A 生成输出文件处理失败 跳过该文件
0x1180100B 输出文件的临时文件被占用 删除/重命名输出目录下的临时文件(<输出文件名>.temp)

【参考文档】

       • HWASAN 原理介绍:https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-stability-address-sanitizer-principle

       • HWASAN 使用指南:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-hwasan#section31022911513

       • HWASAN 最佳实践:https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-stability-hwasan-detection

       • Clang HWASAN 开源文档:https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html

       总结:HWASAN + BinXO 方案通过二进制插桩技术,实现了无源码场景下的内存访问检测,大幅降低了踩内存问题的定位门槛。开发者只需在 DevEco Studio 中勾选两个选项,即可开启全面的内存检测能力,结合 IDE 集成的堆栈跟踪分析工具,能够快速定位内存问题根因,提升应用稳定性。

本文由 @华为开发者联盟 授权发布于人人都是产品经理。未经作者许可,禁止转载

题图来自Unsplash,基于CC0协议

该文观点仅代表作者本人,人人都是产品经理平台仅提供信息存储空间服务

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 目前还没评论,等你发挥!