已关闭
CppCrash 新增 LLVM 工具自动发现脚本与步骤零输入校验门禁 对比报告 #37
fangzy0823创建于  9月3日关闭于  9月7日
fangzy0823
9月3日 创建

CppCrash 报告对比分析综合报告

对比背景

本报告对以下两份 CppCrash 分析报告进行横向对比:

  • 报告 A(原skill):reports/202609031022/CPP_Crash-SIGBUS(非法内存访问)-BUS_ADRALN_同步-7.0B33.md
  • 报告 B(修改后skill):reports/202609031023/CPP_Crash-SIGBUS(非法内存访问)-BUS_ADRALN_同步-7.0B33.md

两份报告分析的是同一崩溃事件:

字段 值
故障时间 2026-07-20 16:59:29.733
故障进程 PID 4472 / com.example.dfx_test / UID 20020205
故障类型 CPP_CRASH (NativeCrash)
信号类型 signo=SIGBUS, code=BUS_ADRALN
崩溃地址 0x0000007fb8039f11
崩溃函数 libentry.so!TriggerStackAlign(napi_env__, napi_callback_info__)+0x2c
崩溃模块 /data/storage/el1/bundle/libs/arm64/libentry.so

一、根因诊断对比

维度 报告 A (1022) 报告 B (1023)
诊断结论 将 SP 修改为非 16 字节对齐地址(0x...f11,仅 1 字节对齐) 通过内联汇编故意将 SP 最低位置 1 破坏 16 字节对齐,随后执行 str x0, [sp] 触发硬件对齐异常
可信度 HIGH HIGH
精确度评价 描述了现象层面(SP 被修改为非对齐地址),未说明如何修改 明确给出了操作手法(orr x0, x0, #0x1),精确到具体汇编指令

结论:两份报告根因判断一致且正确,但报告 B 在诊断精确度上显著优于报告 A。


二、证据链完整性对比

2.1 信号与子码分析

两份报告对 SIGBUS(BUS_ADRALN) 的语义解读基本一致,均正确指出:

  • SIGBUS 表示对齐错误或不存在的物理地址访问
  • BUS_ADRALN 子码表示地址对齐错误
  • AArch64 要求 SP 保持 16 字节对齐

差异:报告 B 额外补充了"精确异常"概念,说明该异常由硬件在指令执行时立即触发(非延迟异常),技术表述更严谨。

2.2 寄存器与故障地址分析

维度 报告 A (1022) 报告 B (1023)
fault_addr 分析 正确识别末位 0x1 违反对齐 正确识别,并明确说明"SP 必须以 0x0 结尾"
sp 分析 指出 sp = fault_addr,说明崩溃发生在 SP 未对齐时执行 SP 相对访存 指出 sp = fault_addr,说明崩溃指令以非对齐 SP 作为访存基址
x0 分析 推测"x0 可能也被设置为该非对齐地址并参与访存"(推测性表述) 确定性描述:x0 保存了被置 1 后的非对齐 SP 值,对应源码指令序列的执行结果(确定性表述,有源码佐证)
esr 分析 提供了 ESR 解码:EC=0x25(Data Abort)、ISS=0x0(Alignment fault) 未单独展开 ESR 解码
评价 分析正确但偏推测性 分析确定且有源码对应

结论:报告 B 的寄存器分析更具确定性(有源码佐证),报告 A 的 ESR 解码更完整。

2.3 调用栈分析

维度 报告 A (1022) 报告 B (1023)
分析深度 分析到 #11 ClickRecognizer::OnAccepted 分析到 #34,覆盖完整触摸事件分发链
调用链语义描述 用户点击 → ArkUI 手势识别 → JS 回调 → N-API → TriggerStackAlign → SIGBUS 用户触摸点击 → 窗口管理器分发 → Ace 框架手势识别 → JS 回调 → N-API → TriggerStackAlign → SIGBUS
JS 源码帧 cppcrash_sigbus.ts:141:34(确认 SIGBUS 测试页面点击事件回调) cppcrash_sigbus.ts:141:34(确认点击 "BUS_ADRALN_同步" 按钮触发调用)
评价 调用链描述到系统框架层即止 调用链描述更完整,覆盖从窗口管理器到触摸事件的全路径

结论:报告 B 的调用链分析更完整,但对根因定位无实质影响(系统帧仅做路径佐证)。

2.4 源码与反汇编(核心差异)

维度 报告 A (1022) 报告 B (1023)
Native 源码 未提供 提供完整源码(app_crash.cpp:163-178),含 __attribute__((optnone)) 和完整内联汇编代码
反汇编 未提供,标记为"需进一步分析" 提供 4 条关键指令反汇编(d6660-d666c),精确标注崩溃指令 str x0, [sp]
源码-反汇编一致性验证 未完成 已完成闭环验证,反汇编指令序列与源码一致
评价 证据链断裂,无法确认触发异常的具体指令 证据链完整,从源码到反汇编形成完整证据闭环

报告 B 提供的关键证据:

源码(app_crash.cpp:163-178):

__attribute__((optnone)) napi_value TriggerStackAlign(napi_env env,
    napi_callback_info info) {
#if defined(__aarch64__)
    asm volatile("mov x0, sp\n"
                 "orr x0, x0, #0x1\n" // 使栈指针未对齐
                 "mov sp, x0\n"       // 设置未对齐栈指针
                 "str x0, [sp]\n"     // 尝试使用未对齐栈 ← 崩溃点
                 :
                 :
                 : "x0", "sp", "memory");
#endif
    napi_value result;
    napi_get_null(env, &result);
    return result;
}

反汇编(test_files/libentry.objdump):

d6660: 910003e0  mov x0, sp          ; x0 = 当前 SP
d6664: b2400000  orr x0, x0, #0x1    ; x0 = SP | 1(破坏对齐)
d6668: 9100001f  mov sp, x0          ; SP = 非对齐值
d666c: f90003e0  str x0, [sp]        ; ← SIGBUS 崩溃指令

结论:这是两份报告质量差距最大的地方。报告 B 完成了从源码到反汇编的完整证据闭环,实现了从"现象推断"到"指令级确认"的跨越。

2.5 Memory Near / Maps 辅助证据

两份报告均确认:

  • fault_addr 0x7fb8039f11 落在 [stack] 映射区间(合法栈地址)
  • pc 落在 libentry.so r-xp 段(正常代码执行段)
  • 栈内存内容正常,排除踩内存场景

差异:报告 B 额外指出"x0/sp 附近栈内存(FaultStack)内容为正常的栈帧数据,无内存破坏迹象,排除踩内存第 2 场景",明确排除了内存破坏可能性。


三、根因模块定界对比

维度 报告 A (1022) 报告 B (1023)
责任领域 应用 应用
责任模块 libentry.so ! TriggerStackAlign+0x2c libentry.so ! TriggerStackAlign+0x2c(源码:app_crash.cpp:166-169,内联汇编 orr/mov/str 指令序列)
定界依据 (1) 崩溃帧位于应用函数 (2) so 路径为应用产物 (3) JS 源码佐证 (1) 崩溃帧位于应用函数 (2) so 路径为应用产物 (3) 源码确认(含注释标注"故障场景:栈指针未对齐导致硬件异常")
评价 定界正确,依据充分 定界正确,源码注释进一步佐证为故意构造的测试场景

四、修复建议对比

维度 报告 A (1022) 报告 B (1023)
建议 1 移除或修正导致 SP 非对齐的代码 移除或条件编译保护(app_crash.cpp:166-169),建议使用 #ifdef DFX_TEST 隔离测试代码
建议 2 增加静态分析或编译选项检查,禁止非对齐 SP 操作 代码审查流程增加内联汇编安全检查项
建议 3 添加防御性单元测试,验证 SP 对齐 Release 构建确认隔离有效;DFX 测试使用独立进程隔离
评价 建议方向正确,但偏泛化 建议精确到行号,可操作性强

五、进一步分析项对比

分析项 报告 A 报告 B
反汇编分析(pc 附近指令) 未完成 已完成
符号文件 BuildID 核对 未完成 已完成
HWASan / ASan 地址越界检测 未完成 未完成
Core Dump / Tombstone 深度解析 未完成 未完成
多次复现对比以排除随机性 未完成 未完成

结论:报告 B 完成了报告 A 标记为"需进一步分析"的两项关键工作(反汇编分析和 BuildID 核对),证据链更加完整。


六、综合评价

评估维度 报告 A 报告 B
根因结论正确性 HIGH HIGH
证据完整性 中等 完整
寄存器分析深度 推测性 确定性
触发指令确认 未确认 已确认
源码定位 仅 JS 层 JS + Native
反汇编证据 缺失 完整
修复建议可操作性 一般 精确
调用链完整度 中等 完整

七、结论与建议

对比结论

  1. 根因判断一致性:两份报告对崩溃根因的判断完全一致,均正确识别为应用函数 TriggerStackAlign 故意破坏 SP 对齐触发 SIGBUS(BUS_ADRALN)。

  2. 证据链完整性差异:报告 B 在证据完整性上有质的提升:

    • 获取并展示了 Native 源码(app_crash.cpp:163-178)
    • 完成了反汇编验证(test_files/libentry.objdump)
    • 实现了从源码到反汇编的完整证据闭环
    • 精确标注了触发异常的具体指令(str x0, [sp])
  3. 分析深度差异:报告 B 的分析更具确定性:

    • 寄存器分析从"推测性"升级为"确定性"(有源码佐证)
    • 修复建议从"泛化"升级为"精确到行号"
    • 根因模块定界增加了源码注释佐证(确认为故意构造的测试场景)
  4. 报告 A 的优势:ESR 解码更完整(EC=0x25, ISS=0x0),报告 B 未单独展开 ESR 分析。

改进建议

对报告 A 的改进建议:

  • 补充 Native 源码定位(app_crash.cpp:163-178)
  • 补充反汇编验证(d6660-d666c 指令序列)
  • 将寄存器分析从推测性表述升级为确定性表述
  • 完成 BuildID 核对并勾选确认

对报告 B 的改进建议:

  • 补充 ESR 解码分析(EC=0x25 Data Abort, ISS=0x0 Alignment fault)
  • 可考虑增加与同类 SIGBUS 案例的横向对比

对后续报告生成的建议:

  • 在报告生成流程中,优先获取 Native 源码和反汇编信息
  • 建立证据链完整性检查清单,确保关键证据项(源码、反汇编、BuildID)在最终报告中均有体现
  • 寄存器分析应尽可能与源码指令序列对应,避免推测性表述

附录:报告质量评分

评分项 报告 A 报告 B 说明
根因判断准确性 10/10 10/10 两者均正确
证据完整性 6/10 9/10 B 有源码+反汇编闭环
寄存器分析深度 7/10 9/10 B 有源码佐证
调用链分析完整度 7/10 9/10 B 覆盖更完整
修复建议可操作性 6/10 9/10 B 精确到行号
进一步分析完成度 5/10 8/10 B 完成关键分析项
综合评分 6.8/10 9.0/10 B 显著优于 A
likedislike
Ffangzy0823
9月3日 修改标题为 “CppCrash 增加llvm_tools调用脚本 对比报告”,原标题为“CppCrash 增加llvm_tools查找、调用脚本 对比报告”
Ffangzy0823
9月3日 关联了pull request:feat: 步骤零新增输入校验——日志类型与堆栈信息门禁
Ffangzy0823
9月3日 修改了issue 的描述
Ffangzy0823
9月3日 修改标题为 “CppCrash 对比报告”,原标题为“CppCrash 增加llvm_tools调用脚本 对比报告”
fangzy0823
9月3日 评论:

对比分析报告:202609031118(原skill) vs 202609031119(修改后skill)

执行摘要

本报告对比分析了 output\202609031118 和 output\202609031119 两个目录的输出结果。两个版本均包含相同的两个日志文件:

  1. CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.log - CppCrash 日志
  2. appfreeze-com.example.dfx_test-20020194-20260718145543386.log - AppFreeze 日志

核心发现:

  • 202609031118:错误地使用 CppCrash 分析技能分析了 AppFreeze 日志,违反了技能职责边界
  • 202609031119:正确识别并拒绝分析 AppFreeze 日志,符合技能职责规范

详细对比

1. CppCrash 日志分析对比

202609031118 版本

  • 输出文件:CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.log (1,145 字节)
  • 生成报告:reports\202609031118\CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.md (12,310 字节)
  • 根因定位:
    • 应用 NAPI 函数 AbortProcess(位于 libentry.so)主动调用 abort() 终止进程
    • 触发链:用户点击 Button → MMI 投递触摸事件 → ArkUI 点击识别 → JS 回调 (cppcrash_sigabrt.ts:361:34) → AbortProcess NAPI → abort() → raise(SIGABRT)
  • 关键证据:
    • SI_TKILL + from:31335:20020205 表明信号由本进程自身投递
    • #02 帧 AbortProcess 位于应用产物路径 /data/storage/el1/bundle/libs/arm64/libentry.so
    • HiLog 时序:15:06:18.186 点击识别 → 15:06:18.189 收到 SIGABRT,间隔 3ms
  • 责任领域:应用侧(正确定界)

202609031119 版本

  • 输出文件:CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.log (957 字节)
  • 生成报告:reports/202609031119/CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.md (10,295 字节)
  • 根因定位:
    • 与 202609031118 完全一致
    • 应用 NAPI 函数 AbortProcess 主动调用 abort() 终止进程
    • 相同的触发链和证据链
  • 责任领域:应用侧(正确定界)

CppCrash 分析结论

✅ 两个版本在 CppCrash 分析上表现一致,均正确定位根因、提供完整证据链、准确定界责任领域。


2. AppFreeze 日志处理对比(关键差异)

202609031118 版本

  • 输出文件:appfreeze-com.example.dfx_test-20020194-20260718145543386.log (1,331 字节)
  • 生成报告:reports\202609031118\appfreeze-com.example.dfx_test-20020194-20260718145543386.md (22,216 字节,384 行)
  • 处理方式:
    • ⚠️ 错误地使用 CppCrash 分析技能分析了 AppFreeze 日志
    • 虽然识别出这是 AppFreeze(APP_INPUT_BLOCK)而非 CppCrash
    • 但仍然生成了完整的分析报告
  • 报告内容:
    • 正确识别故障类型:AppFreeze(APP_INPUT_BLOCK)
    • 根因定位:主线程在 WaitThread 函数中执行 std::thread::join() 同步等待 6 个工作线程,但工作线程的 running 标志永远为 true(停止逻辑被注释掉),导致主线程永久阻塞
    • 源码定位:napi_init.cpp:256-290,running = false 的停止逻辑在第 288-289 行被注释掉
  • 问题:
    • ❌ 违反了技能职责边界:CppCrash 分析技能不应处理 AppFreeze 日志
    • ❌ 可能造成技能职责混淆,降低系统的可维护性

202609031119 版本

  • 输出文件:appfreeze-com.example.dfx_test-20020194-20260718145543386.log (1,974 字节)
  • 生成报告:无(未生成报告)
  • 处理方式:
    • ✅ 正确地拒绝分析 AppFreeze 日志
    • 明确输出:"该日志不是 CppCrash 故障日志,无法使用本技能分析"
    • 提供了详细的判定依据:
      • 文件名前缀为 appfreeze- 而非 cppcrash-
      • Reason 为 APP_INPUT_BLOCK(应用输入阻塞)
      • 无 CppCrash 必备特征(无 Signal、无寄存器、无 Native 调用栈)
    • 建议用户使用专门的 AppFreeze 分析技能
  • 优点:
    • ✅ 严格遵守技能职责边界
    • ✅ 提供清晰的判定依据和建议
    • ✅ 符合技能设计规范

AppFreeze 处理结论

✅ 202609031119 版本表现正确,正确识别并拒绝分析非 CppCrash 日志
❌ 202609031118 版本存在严重问题,越界处理了 AppFreeze 日志


对比总结表

评估维度 202609031118 202609031119 优胜版本
CppCrash 根因定位 ✅ 正确 ✅ 正确 平手
CppCrash 证据链完整性 ✅ 完整 ✅ 完整 平手
CppCrash 责任定界 ✅ 正确(应用侧) ✅ 正确(应用侧) 平手
CppCrash 报告质量 ✅ 高质量(12,310 字节) ✅ 高质量(10,295 字节) 平手
AppFreeze 识别 ✅ 识别为 AppFreeze ✅ 识别为 AppFreeze 平手
AppFreeze 处理 ❌ 越界分析 ✅ 正确拒绝 202609031119
技能职责遵守 ❌ 违反职责边界 ✅ 严格遵守 202609031119
输出规范性 ⚠️ 生成了不应有的报告 ✅ 未生成越界报告 202609031119

结论与建议

总体评价

202609031119 版本更优,原因如下:

  1. 技能职责边界清晰:正确识别 AppFreeze 日志并拒绝分析,严格遵守 CppCrash 分析技能的职责范围
  2. 输出规范:未生成越界的 AppFreeze 分析报告,避免了技能职责混淆
  3. 用户指引明确:提供了清晰的判定依据和建议,引导用户使用正确的技能

202609031118 版本存在严重问题:

  1. 越界处理:虽然正确识别了 AppFreeze 日志,但仍然进行了分析,违反了技能职责边界
  2. 输出混乱:生成了不应有的 AppFreeze 分析报告,可能导致技能职责混淆
  3. 可维护性风险:如果允许技能越界处理,将降低系统的可维护性和可扩展性

改进建议

系统层面建议

  1. 统一技能路由机制:在所有分析技能入口建立统一的日志类型校验机制
  2. 建立技能职责文档:明确每个技能的处理范围和拒绝规则
  3. 增加自动化测试:验证技能在接收到非目标日志类型时的拒绝行为

附录:关键文件清单

202609031118 输出

output/202609031118/
├── CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.log (1,145 字节)
└── appfreeze-com.example.dfx_test-20020194-20260718145543386.log (1,331 字节)

reports/202609031118/
├── CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.md (12,310 字节) ✅
└── appfreeze-com.example.dfx_test-20020194-20260718145543386.md (22,216 字节) ❌ 越界报告

202609031119 输出

output/202609031119/
├── CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.log (957 字节)
└── appfreeze-com.example.dfx_test-20020194-20260718145543386.log (1,974 字节)

reports/202609031119/
└── CPP_Crash-SIGABRT(进程主动终止)-SI_TKILL_同步.md (10,295 字节) ✅

报告生成时间:2026-09-03
对比分析完成:2026-09-03

likedislike
Ffangzy0823
9月3日 修改了issue 的描述
Ffangzy0823
9月3日 修改了issue 的描述
openharmony_ciopenharmony_ci成员
9月7日 关闭了 issue
openharmony_ciopenharmony_ci成员
9月7日 issue状态由 待办的 改变为 已完成
Ffangzy0823
9月8日 修改标题为 “CppCrash 新增 LLVM 工具自动发现脚本与步骤零输入校验门禁 对比报告”,原标题为“CppCrash 对比报告”