Skip to content
Back to skills

Hmos Cppcrash Analysis

ASecurity

DFX Skills,分析 HarmonyOS/OpenHarmony 应用的 CppCrash(Native 层崩溃)日志, 基于信号、寄存器、Native 调用栈、符号和内存证据定位根因并给出修复建议。 当输入包含 cppcrash、NativeCrash、Reason:Signal、Fault thread info、Registers、 Memory near registers、Native .so 调用栈、SIGSEGV/SIGABRT/SIGILL/SIGBUS/SIGFPE, 或 GWP-ASan 报告时使用。若用户只说“应用崩溃/闪退”但没有 JS 或 Native 证据, 先识别日志类型;仅在确认是 Native Crash 后使用本技能。

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 22, 2026
developmentpythonbashsqlapi

Works with

  • api

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned September 22, 2026

npx -y skills add IsKenKenYa/skills --skill hmos-cppcrash-analysis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hmos Cppcrash Analysis?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hmos Cppcrash Analysis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iskenkenya-hmos-cppcrash-analysis/badge)](https://www.skillsdirectory.com/skills/iskenkenya-hmos-cppcrash-analysis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hmos-cppcrash-analysis
description: >-
  DFX Skills,分析 HarmonyOS/OpenHarmony 应用的 CppCrash(Native 层崩溃)日志,
  基于信号、寄存器、Native 调用栈、符号和内存证据定位根因并给出修复建议。
  当输入包含 cppcrash、NativeCrash、Reason:Signal、Fault thread info、Registers、
  Memory near registers、Native .so 调用栈、SIGSEGV/SIGABRT/SIGILL/SIGBUS/SIGFPE,
  或 GWP-ASan 报告时使用。若用户只说“应用崩溃/闪退”但没有 JS 或 Native 证据,
  先识别日志类型;仅在确认是 Native Crash 后使用本技能。
metadata:
   author: Huawei Reliability Technology Lab
   version: 1.3.0
---

# CppCrash 故障分析技能

## 核心原则

1. 先提取事实,再匹配故障模式;不得用单个栈帧直接推导深层根因。
2. 关键日志报告用于导航,原始日志仍是证据源。提取结果缺失字段时必须回读原始日志。
3. 区分崩溃点、首个非运行时调用方和首个应用侧帧,不把系统运行时帧直接当作业务根因。
4. `.so` 路径只能辅助判断代码归属,不能单独证明责任归属。
5. 区分第一现场和延迟崩溃。GC、allocator、容器或运行时栈可能只是内存破坏后的触发点。
6. 使用证据等级:检测器明确报告 > 指令/寄存器联合证据 > 多项栈特征 > 单一模块特征。
7. 修复建议必须与根因责任领域一致:系统侧根因只给系统侧修改,应用侧根因只给应用侧修改;不得用应用规避方案替代系统缺陷修复。

## 分析流程

### 步骤零:环境与输入检查

1. 确认 Python 3.8 或更高版本可用:

   ```bash
   python --version
   ```

   Windows 中没有 `python` 命令时尝试 `py -3`。脚本只使用 Python 标准库,无需安装第三方依赖。

2. 将包含本文件的目录记为 `<skill-root>`。调用脚本时使用完整路径,不依赖当前工作目录:

   ```bash
   python "<skill-root>/scripts/main.py" -p "<cppcrash文件或目录>"
   ```

3. 用户要求分析目录内全部日志时增加 `--all`:

   ```bash
   python "<skill-root>/scripts/main.py" -p "<日志目录>" --all
   ```

4. 检查输入是否存在、是否可读。若脚本未识别日志,直接检查原始文件中的 `Reason:`、
   `Fault thread info:`、`Reason:GWP-ASAN` 和 `*** GWP-ASan detected a memory error ***`。

### 步骤一:提取关键日志

完整阅读脚本输出,并在以下情况回读原始日志:

- 报告提示字段或调用栈缺失。
- 需要其他线程完整调用栈、完整 Maps、HiLog 或 GWP-ASan 三段调用栈。
- 日志包含多个故障事件或拼接内容。
- 结论依赖未被提取的上下文。

目录输入默认分析按日志时间或文件修改时间确定的最新一份日志;批量分析必须使用 `--all`。

### 步骤二:选择分析分支

#### GWP-ASan 分支

用户描述或日志内容包含以下任一特征时,读取 `references/gwp_asan.md`:

- `gwpasen`、`gwpasan`、`GWP-ASan` 或 `GWP-ASAN`
- `Reason:GWP-ASAN`
- `*** GWP-ASan detected a memory error ***`

必须保留并分析违规访问、释放和申请调用栈。普通 CppCrash 不加载该 reference。

#### 普通 Native Crash 分支

读取 `references/fault_mode.md`,从 `Reason` 中提取信号、`si_code` 和故障地址:

| 信号 | 基础语义 | 首要分析方向 |
|------|----------|--------------|
| `SIGSEGV(SEGV_MAPERR)` | 地址未映射 | 空基址偏移、悬空指针、越界地址 |
| `SIGSEGV(SEGV_ACCERR)` | 映射权限不允许当前访问 | 写只读页、执行不可执行页、映射状态变化 |
| `SIGILL` | CPU 执行了非法或不受支持的指令 | 指令损坏、错误跳转、ISA/PAC/CFI 问题 |
| `SIGBUS` | 对齐、映射文件或硬件访问异常 | 对齐、mmap 文件变化、对象访问错误 |
| `SIGABRT` | 进程主动终止 | LastFatalMessage、assert、未捕获异常、检测器报告 |
| `SIGFPE` | 算术异常 | 除零、溢出或无效算术操作 |

信号只描述故障机制,不等于代码根因。

### 步骤三:按需加载知识库

只读取与关键日志匹配的 reference。允许命中多项,但不要读取无关文件。

| 日志特征 | 读取 reference |
|----------|----------------|
| `libace_compatible`、`libace_ndk`、`OHOS::Ace`、XComponent、UI 节点 | `references/arkui.md` |
| `libnative_rdb`、`libsqlite`、`libnative_appdatafwk`、`librelationalstore` | `references/arkdata.md` |
| ArkWeb、WebView、`libarkweb_engine`、crashpad、Web GPU | `references/arkweb.md` |
| `libark_jsruntime`、`libace_napi`、N-API、JS GC/OOM、`LoadJSPandaFile`、`load hsp failed`、`Crash occured on ProcessAll` | `references/jsruntime.md` |
| `RenderService`、`OHOS::Rosen`、NativeWindow、BufferQueue | `references/render_service.md` |
| `libv8_shared`、`libjsvm`、`OH_JSVM_*`、`DestroyEnv`、`HandleScope`、`openHandleScopes`、JSVM Fatal Error | `references/jsvm.md` |
| `librosen_text`、FontCollection、Paragraph 文本对象 | `references/rosen_text.md` |
| allocator/CFI/PAC/StackProtector/代码段异常等内存破坏特征 | `references/memory_corruption.md` |
| `edata_heap_remove`、`emap_update_edata_state`;或故障地址以 `0x006b` / `0x6b6b` 开头且 `#00` 为 `/system/lib64/` 系统栈 | `references/memory_corruption_second_scene.md` |

满足以下四类表现之一时额外读取 `references/multithreading.md`:

1. 日志包含 `CheckThread` 和 `ecma_vm cannot run in multi-thread`。
2. 主线程或工作线程栈同时包含业务/组件代码与 N-API、JS Runtime 或 JS 绑定调用,且故障地址为
   NULL 小偏移、连续可打印 ASCII 字符型地址或其他疑似对象损坏地址。
3. `OS_GC_Thread` 的栈只有 GC 帧,并在 `ConcurrentMarker`、`NonMovableMarker` 或
   `ProcessMarkStack` 等标记阶段访问非法地址。
4. `OS_GC_Thread` 的栈只有 GC 帧,并在 `EvacuateObject`、`FullGCRunner` 或
   `CompressGCMarker` 等搬迁阶段出现 `unreachable type` 或非法对象类型。

第 1 类是跨线程使用 `env` 的第一现场。第 2 至第 4 类通常是 JS 对象被破坏后的延迟崩溃;
优先排查跨线程 `env`,但需结合线程归属、N-API 路径或检测结果确定最终可信度。

reference 发生冲突时,以证据等级更高的规则为准。模块栈模式不得覆盖检测器报告或明确的寄存器/指令证据。

命中 `references/memory_corruption_second_scene.md` 时,只能将当前崩溃栈定界为踩内存的第2现场。
`#00` 系统模块是损坏内存的访问方或检测点,不能据此直接认定为非法踩写源;缺少第一现场证据时,
必须明确说明踩写模块尚未定位。

### 步骤四:建立证据链

#### 1. 信号、地址和寄存器

- `fault_addr` 接近 0 只表示疑似空基址加成员偏移,需结合实际访存指令、基址寄存器及
  N-API/线程归属证据判断是否为跨线程破坏后的延迟表现。
- `fault_addr` 按字节解析后包含连续可打印 ASCII 字符时,说明指针或对象字段可能被字符数据覆盖;
  这是内存破坏证据,不能脱离线程与调用链单独确认跨线程根因。
- 随机地址、allocator、GC 或容器栈只能作为内存破坏候选,除非有检测器或联合证据。
- 从 PC 附近指令确定读写方向、参与计算的寄存器和实际访问地址。
- Maps 区间采用左闭右开语义:`start <= address < end`。

#### 2. 调用栈分层

按以下层级分别记录,不得混为一个“业务首帧”:

| 层级 | 含义 |
|------|------|
| 崩溃帧 | `#00`,进程最终触发信号的位置 |
| 首个非运行时调用方 | 跳过 libc、abort、Ark Runtime、N-API 桥接层后的第一个调用模块 |
| 首个应用侧帧 | 路径或构建信息能够确认属于应用产物的第一帧 |

没有应用帧时不得伪造应用责任模块。系统栈也可能由错误入参、生命周期或回调契约触发。

#### 3. 责任领域与修复建议对齐

输出修复建议前,必须依据第一现场、违规访问/释放/申请栈、调用契约、寄存器/指令和源码证据,将责任领域判定为:应用、系统、混合或未定。

- **系统侧根因**:证据链确认缺陷位于系统服务、系统框架、系统库或系统 API 实现时,只输出对应系统模块的代码/架构修改,例如空值与边界修复、对象生命周期和并发修复、锁序调整、接口契约修正。不得要求应用修改调用方式、增加兜底或规避系统缺陷来充当根因修复。
- **应用侧根因**:证据链确认应用错误入参、生命周期、越界、跨线程或接口误用时,只输出应用侧修改。
- **混合责任**:双方都有直接缺陷时分栏输出,先写主要责任方;应用侧临时规避必须明确标注,不能替代系统侧修复。
- **责任未定**:只有系统栈、只有应用调用入口或当前仅为踩内存第2现场时,不强行给跨责任域修改方案;输出继续定界所需的符号、第一现场、源码或检测器证据。

`.so` 路径仅用于代码归属辅助,责任结论仍须由根因证据决定。根因位于系统侧时,即使故障进程是三方应用,也必须给系统侧修改建议。

#### 4. 符号化、反汇编和源码

仅在材料齐全时执行,不得将其写成无条件必选步骤:

1. 有匹配 BuildID 的 `.so` 和符号时运行:

   ```bash
   llvm-addr2line -pCfie "<so文件>" "<pc相对偏移>"
   ```

2. 行号仍不足以判断多参数调用、虚表、函数指针或访存寄存器时运行:

   ```bash
   llvm-objdump -dS -l -C "<so文件>" > "<so文件名>.objdump"
   ```

3. 用户提供源码后,结合行号上下文检查空值、边界、所有权、线程和回调时序。
4. 缺少符号、二进制或源码时明确列为缺失信息,不猜测函数行号或代码实现。

#### 5. 符号表反解状态门禁

输出修复建议前必须判断关键责任候选栈帧是否已完成符号表反解:

- 用户明确说明已使用与故障版本 BuildID 匹配的符号文件,且提供了关键责任候选帧的函数名或源码行,才视为已反解。
- 用户未说明反解过程、未核对 BuildID,或关键责任候选帧仍仅有裸地址、`<so>+offset` 或 `unknown`,均视为未反解。
- 应用侧根因或应用侧责任候选未反解时,【修复建议】或【下一步建议】的第 1 项要求提供匹配 BuildID 的应用 `.so`/符号;系统侧根因或系统侧责任候选未反解时,要求提供对应系统模块的匹配符号、源码或可符号化版本。不得在已确认系统侧根因后仍把“反解应用帧”作为首要修改建议。
- 责任未定时,按证据指向分别列出需要反解的候选模块;在反解完成前只给定界建议,不猜测具体代码修改。
- 上述要求适用于常规 CppCrash、踩内存第2现场和 GWP-ASan 场景;不得只在“是否需要进一步分析”中勾选符号文件核对而省略必要的责任模块符号化建议。

#### 6. HiLog

日志含 `HiLog:` 且需要还原崩溃前业务时运行:

```bash
python "<skill-root>/scripts/extract_hilog.py" "<faultlog文件>"
```

HiLog 仅作触发路径和时序辅助证据,不能单独作为根因。

---

## 输出格式要求

读取参考文件:`references/fault_mode.md`

根据分析结果严格选择一个模板,不得混用:

- 命中 `references/memory_corruption_second_scene.md` 时,只能使用“模板B:踩内存场景”。
- 其他 CppCrash 场景使用“模板A:常规CppCrash场景”。
- 所有模板中的【修复建议】必须服从“责任领域与修复建议对齐”规则;reference 中的场景示例不得覆盖该规则。

### 模板A:常规CppCrash场景

```
================================================================================
                        CppCrash 问题综合分析报告
================================================================================

【故障基本信息】
故障时间     : <从日志提取,如 2025-04-20 10:23:45.678>
故障进程     : <PID / 进程名 / UID>
故障类型     : CPP_CRASH (NativeCrash)
信号类型     : <signo=SIGXXX, code=XXX_YYY>
崩溃地址     : <fault addr,如 0x0000000000000010>
崩溃函数     : <调用栈 #00 帧,如 libxxx.so!Foo::Bar(int)+0x24>
崩溃模块     : <so 路径,如 /data/storage/el1/.../libfoo.z.so>
故障原因描述 : <日志中的原始 Reason 字段>


【根因分析】
诊断结果 : <一句话概括根因,如:"空指针解引用——this 指针为 nullptr 时调用虚函数">
故障类别 : <空指针 / UAF / 栈溢出 / 数据竞争 / 越界访问 / 死锁 / 除零 / 对齐错误 / ...>
可信度   : HIGH / MEDIUM / LOW


【三级根因定位】(依据 CPP_CRASH 故障模式库)
┌──────────┬────────────────────────────────┬─────────────────────────────────┐
│   层级   │              根因              │           匹配依据              │
├──────────┼────────────────────────────────┼─────────────────────────────────┤
│ 一级根因 │ CPP_CRASH                      │ <name_=CPP_CRASH 原始日志片段>  │
│          │                                 │                                 │
│ 二级根因 │ <信号名称,如 SIGSEGV>         │ <signo=XXX 原始日志片段>        │
│          │ (1.1.1.X.0)                    │                                 │
│ 三级根因 │ <si_code 名称,如 SEGV_MAPERR> │ <code=XXX 原始日志片段>         │
│          │ (1.1.1.X.Y)                    │                                 │
└──────────┴────────────────────────────────┴─────────────────────────────────┘


【证据链】

1. 信号与子码语义分析
   原始日志:
   <Reason / Fault thread info / signal 行原始片段>
   解读:
   <基于故障模式库对 signo + code 组合的语义说明>

2. 寄存器与故障地址分析
   原始日志:
   <x0-x30 / pc / lr / sp 等关键寄存器原始片段>
   解读:
   <如 fault_addr=0x10 接近 0,判定为对成员偏移 0x10 的访问,
     结合 x0=0 说明 this 指针为空 等>

3. 调用栈关键帧
   原始日志:
   #00 pc 000xxxxx  /data/.../libfoo.z.so   (Foo::Bar(int)+0x24)
   #01 pc 000xxxxx  /data/.../libfoo.z.so   (Foo::Run()+0x80)
   #02 pc 000xxxxx  /system/lib64/libxxx.so (...)
   解读:
   <关键帧所在模块归属 /data 还是 /system;调用链语义>

4. 源码行号(如符号可用)
   <file:line 定位,如 foo.cpp:123>

5. Memory Near / Maps 辅助证据(如有)
   <如 fault_addr 附近内存映射、堆/栈 /匿名页归属>


【根本原因】
直接原因 : <导致崩溃的直接代码/数据问题,如:"Obj 析构后仍被持有的裸指针
             在 2 号线程继续调用 Release()">
深层原因 : <设计/契约/流程层面的深层原因,如:"生命周期管理未使用智能指针,
             跨线程共享对象缺少引用计数保护">
触发路径 : <从触发点到崩溃点的完整调用链>


【根因模块】
责任领域 : <应用 / 系统>
责任模块 : <so 路径 + 具体函数,如:/data/storage/el1/.../libfoo.z.so !
            Foo::Bar(int)+0x24>
定界依据 :
  (1) 基于故障根本原因定界:<说明根因是应用使用不当 / 系统 API 缺陷 / ...>
  (2) so 路径归属:<如 /data 开头 → 应用侧;/system 开头 → 系统侧>
  (3) 死锁场景补充:<若为死锁,标注持锁线程与持锁函数>


【修复建议】
1. <按责任领域填写:系统侧根因写对应系统模块的直接代码修复;应用侧根因写应用代码修复;责任模块未反解时先要求该责任模块的匹配符号>
2. <针对同一责任领域深层原因的架构改进,如生命周期、锁序、边界或接口契约修复>
3. <由责任模块实施的防御性改进和回归用例;不得把另一责任域的规避措施写成根因修复>


【是否需要进一步分析】
[ ] 反汇编分析(pc 附近指令)
[ ] HWASan / ASan 地址越界检测
[ ] 符号文件 BuildID 核对
[ ] Core Dump / Tombstone 深度解析
[ ] 多次复现对比以排除随机性

================================================================================
```

### 模板B:踩内存场景

**⚠️ 注意:踩内存场景下,【根本原因】和【根因模块】部分字段不适用,无需填写。**
**⚠️ 注意:请不要泛化增加字段。**

严格按照以下结构输出结论:

```
================================================================================
                        CppCrash 问题综合分析报告
================================================================================

【故障基本信息】
故障时间     : <从日志提取>
故障进程     : <PID / 进程名 / UID>
故障类型     : CPP_CRASH (NativeCrash)
信号类型     : <signo=SIGXXX, code=XXX_YYY>
崩溃地址     : <fault addr>
崩溃函数     : <调用栈 #00 帧>
崩溃模块     : <so 路径>
故障原因描述 : <日志中的原始 Reason 字段>


【根因分析】
诊断结果 : <一句话概括根因,如:"jemalloc堆元数据被踩写损坏导致崩溃">
故障类别 : 踩内存第2现场
可信度   : HIGH / MEDIUM / LOW


【三级根因定位】(依据 CPP_CRASH 故障模式库)
┌──────────┬────────────────────────────────┬─────────────────────────────────┐
│   层级   │              根因              │           匹配依据              │
├──────────┼────────────────────────────────┼─────────────────────────────────┤
│ 一级根因 │ CPP_CRASH                      │ <name_=CPP_CRASH 原始日志片段>  │
│          │                                │                                 │
│ 二级根因 │ <信号名称,如 SIGSEGV>         │ <signo=XXX 原始日志片段>        │
│          │ (1.1.1.X.0)                    │                                 │
│ 三级根因 │ <si_code 名称,如 SEGV_MAPERR> │ <code=XXX 原始日志片段>         │
│          │ (1.1.1.X.Y)                    │                                 │
└──────────┴────────────────────────────────┴─────────────────────────────────┘


【证据链】(⚠️ 仅限以下2项,禁止扩展)

1. 信号与子码语义分析
   原始日志:
   <Reason / Fault thread info / signal 行原始片段>
   解读:
   <基于故障模式库对 signo + code 组合的语义说明>

2. 寄存器与故障地址分析
   原始日志:
   <x0-x30 / pc / lr / sp 等关键寄存器原始片段>
   解读:
   <分析寄存器值与崩溃地址的关系>

【根因模块】
责任领域 : 未定(当前仅为踩内存第2现场)
定界依据 : <参考**踩内存第2现场定界专项分析**;不得因 #00 位于 /system 或进程属于应用而提前定责>

【下一步建议】
1. <提供与责任候选模块匹配 BuildID 的未剥离 .so/符号文件;候选为系统模块时提供系统符号,候选为应用模块时提供应用符号,反解到函数及源码行后重新定界>
2. 获取现网 GWP_ASan 地址越界日志或其他踩内存第1现场日志,依据第一现场确定责任领域后再输出对应侧修复
   链接:https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-stability-gwpasan-detection
3. 在责任候选模块可控构建中开启 HWASan 并复现,分析 HWASan 报告定位越界写操作源头
   链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-hwasan


【是否需要进一步分析】
[ ] 符号文件 BuildID 核对
[ ] 反汇编分析(pc 附近指令)
[ ] HWASan / ASan 地址越界检测
[ ] Core Dump / Tombstone 深度解析
================================================================================
```

Files in this skill

  • SKILL.md20.5 KB
  • changelog/CHANGELOG.md2.8 KB
  • references/arkdata.md17.2 KB
  • references/arkui.md13.7 KB
  • references/arkweb.md7 KB
  • references/fault_mode.md6.4 KB
  • references/gwp_asan.md11 KB
  • references/jsruntime.md16.7 KB
  • references/jsvm.md13.5 KB
  • references/libuv.md10.3 KB
  • references/memory_corruption.md9.4 KB
  • references/memory_corruption_second_scene.md3.4 KB
  • references/multithreading.md14.1 KB
  • references/render_service.md15.5 KB
  • references/rosen_text.md2.2 KB
  • scripts/__init__.py129 B
  • scripts/collector.py129 B
  • scripts/common.py129 B
  • scripts/crash_log.py130 B
  • scripts/extract_hilog.py129 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…