Open
[aarch64] v2.7-h5补丁两处缺陷修复:桩内异常无法unwind(call风格跳板)及IsEqual对无operator==类型编译失败(h4逻辑回归) #2
JankinEEAdd on Sep 29
Sep 29 Associated pull request
25 days ago Associated pull request
JankinEE
25 days ago Comments:
25 days ago Comments:
修复PR已更新:https://gitcode.com/cann-src-third-party/mockcpp/merge_requests/29 (原PR #28因不支持改目标分支已关闭)
应看护人安排,新PR提交至 v2.7.x-h6 分支:新增 mockcpp-2.7-h6.patch(即原修复内容,对h5补丁的两处修复),并删除被取代的历史补丁(mockcpp-2.7.patch / mockcpp-2.7_py3.patch / mockcpp-2.7-h5.patch)与源码包副本(tar.gz / zip,历史分支与既有release中仍可获取);分支保留 Readme.opensource(三方软件合规元数据)与 mockcpp-2.7-h6.patch。


JankinEE
25 days ago Comments:
25 days ago Comments:
调整说明:源码包 mockcpp-2.7.tar.gz / mockcpp-2.7.zip 保留在 v2.7.x-h6 分支(经确认与 OBS/release 资产逐字节一致,消费方虽从 OBS/release 取包,但按评审意见保留),PR #29 仅清理历史补丁文件(mockcpp-2.7.patch / mockcpp-2.7_py3.patch,h5 补丁重命名为 h6 并纳入修复)。


背景
hcomm 仓(https://gitcode.com/cann/hcomm)在 aarch64 环境打通全量单元测试时,将 mockcpp 从 v2.7-h4 升级到 v2.7-h5(即本仓 PR #18 合入的
mockcpp-2.7_aarch64.patch,对应 runtime 仓 PR #701)。升级解决了 h4 单条 B 指令 ±128MB 跳转距离限制的问题,但实测暴露出 v2.7-h5 补丁的两处缺陷,已在 hcomm 侧以仓内兼容补丁临时规避,现回馈本仓,建议合入并发布 v2.7-h6。消费方 hcomm 侧的适配 PR:https://gitcode.com/cann/hcomm/pull/5664 (内含两个临时兼容补丁,本 issue 合入后可删除)
问题一:桩内抛出的 C++ 异常无法穿过 hook,触发 std::terminate
现象
任何"桩内抛异常"的用例(全 mockcpp 生态常见用法)在 aarch64 下全部失败:
hcomm 仓实测受影响用例 26 处(异常注入类:
.will(throws(...))、invoke 桩内 throw),无一幸免。根因
v2.7-h5 的
SET_JMP_CODE(src/JmpCodeAARCH64.h)为 call 风格跳板:stp x29, x30, [sp,#-16]! // 压栈 movz/movk x30, target // 装载 hook 地址到 x30 blr x30 // 调用 hook ldp x29, x30, [sp],#16 // 弹栈 ret该跳板是运行时写到被 hook 函数入口的手写机器码,没有任何 .eh_frame/unwind 信息。桩内(或 mockcpp 机制内,如 ChainableMockMethodBase 的 catch 后 MOCKCPP_REPORT_FAILURE 重抛)抛出的异常,unwinder 走到 hook 的返回地址(即跳板缓冲区内的地址)时找不到 unwind 记录,直接
std::terminate。对照:x86 的 JmpCodeX86 是 5 字节
jmp rel32,不建立任何栈帧,hook 直接返回原调用者,异常沿正常编译帧 unwind 回被测代码的 catch 分支——所以该缺陷为 aarch64 的 h5 跳板特有。修改方案:br x16 寄存器跳转风格
movz x16, #imm16 // 将 hook 函数完整 64 位地址装入 x16 movk x16, #imm16, lsl #16 movk x16, #imm16, lsl #32 movk x16, #imm16, lsl #48 br x16 // 无链接跳转设计依据(AAPCS64):
ret直接返回原调用者(x30 仍为原调用者返回地址),SP 保持 16 字节对齐;-falign-functions=32保证不越过函数边界;编码(
br x16= 0xD61F0200,movz/movk 基址 0xD2800010/0xF2800010,与现行 x30 版本仅寄存器号不同)已在 hcomm 仓验证。问题二:IsEqual 对无 operator== 的类型编译失败(h4 逻辑回归)
现象
任何无
operator==的自定义类型进入IsEqual<T>(典型路径:returnValue(结构体)→ValueHolder<T>::getConstraint()为虚函数,类实例化即强制实例化eval())即编译失败:根因
v2.7-h4 的
mockcpp-2.7_py3.patch中 IsEqual.h 的 eval() 有针对 class/union 类型的 memcmp 分支:if constexpr (std::is_class<T>::value || std::is_union<T>::value) { return !memcmp((void *)&val, (void *)&expectedValue, sizeof(T)); } else { return any_cast<T>(val) == expectedValue; }v2.7-h5 补丁基于原始 mockcpp-2.7 包重新生成时丢失了这段逻辑(h4/h5 补丁逐文件对比,IsEqual.h 的差异仅有此一处 + 无关的 unique_ptr 特化删除)。实测对比:v2.7-h4 可编译的同批代码,换 v2.7-h5 后
returnValue(Hccl::CollAlgOpReqDef结构体)等用法全部编译失败。修改方案
在 v2.7-h5 补丁的 IsEqual.h 段恢复上述 if-constexpr 分支(即 h4 原有逻辑,逐行恢复),并补充
#include <type_traits>。验证情况
上述两处修改以仓内兼容补丁形式应用于 hcomm 仓(https://gitcode.com/cann/hcomm/pull/5664):
期望
v2.7.x-h5分支的补丁文件(或新增 v2.7-h6 补丁);关联: