您好,感谢反馈!按 cann/ops-math@584b2ea6cbaeba684a51a74296d82d4d50ab3b0f 核查,第一段的形状推导确实存在对 diagonal 极值不安全的有符号运算,不能只依赖后续内部错误返回来处理这些输入。
问题分析
InferDiagOutShape在一维输入时先计算 inputLength + std::abs(diagonal):INT64_MIN 的正绝对值无法用 int64 表示;对于长度 5,INT64_MAX + 5 也超出边长的表示范围。二维负偏移分支则先计算 -diagonal,同样无法安全处理 INT64_MIN。CheckDiagonal 的空边界判断还有同类取负操作。溢出后再检查输出 shape 已经太晚;非法长度可能继续进入形状处理,与您报告的进程异常相符,但具体 SIGABRT 触发点尚未独立复现确认。
当前第一段入口在类型、输入维数检查后就调用上述推导,没有先完成 diagonal 极值及输出尺寸可表示性检查。一维后续的 DiagFlat还会再次计算边长,因此上下层的安全条件也需保持一致。
处理方向
一个可行方案是在 InferDiagOutShape 之前完成受检算术与范围检查,非法参数明确返回 ACLNN_ERR_PARAM_INVALID(161002):一维先处理不可取绝对值的极值,再验证输入长度与偏移绝对值之和,以及输出元素总数能否表示;二维改用不需要对任意 diagonal 直接取负的安全比较,避免生成负长度。不能先执行有符号溢出,再通过结果是否为负来补救。
同时需保留或明确空输出边界的约定:源码专门处理了二维 diagonal==列数、diagonal==-行数 的空对角线情况,而资料约束比这一行为更窄。极值防御应先解决崩溃风险,不能未经兼容评估就顺带改变全部普通越界输入的行为;返回码说明也可同步明确值域和不可表示输出尺寸的限制。
回归可覆盖一维、二维的 INT64_MIN/INT64_MAX 及邻近值、普通合法偏移和现有空输出边界,分别检查第一段错误码与正常输出 shape。您已提供环境和最小对照,无需重复补交;我们会继续确认形状推导的安全检查与接口约定。


现象
调用
aclnnDiagGetWorkspaceSize时,diagonal=INT64_MIN且输入为 2 维,进程以 SIGABRT 退出(rc=134,core dumped),没有返回任何错误码。同一份二进制在合法diagonal上返回 0。self=float32[3,4]、diagonal=1、out=[3]ret=0self=float32[3,4]、diagonal=-9223372036854775808、out=[0]rc=134,无返回码同族形态:
self=float32[5](1 维)+diagonal=INT64_MIN或INT64_MAX同样 abort;diagonal=INT64_MIN+2、-INT64_MAX返回561103,不崩溃。期望
资料《aclnnDiag》"约束说明"写明:输入为 2 维时
diagonal应满足-(m-1) <= diagonal <= (n-1)。越界属于非法入参,按 aclnn 错误码约定应返回161002(ACLNN_ERR_PARAM_INVALID)。公开接口收到非法属性时应返回错误码,不应让调用进程崩溃。环境
cann/ops-math,master 最新提交584b2ea6(复现前git fetch核对,-diagonal/rows + diagonal/std::abs(diagonal)仍在)复现步骤
repro_diag.cpp。g++ -std=c++17 -O2 repro_diag.cpp -o repro_diag -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 -lascendcl -lopapi -lnnopbase./repro_diag ctrl,打印ret=0。./repro_diag defect,打印diagonal=-9223372036854775808 ->后进程 abort;echo $?为134。self形状改为{5}、out形状改为{0},diagonal分别取INT64_MIN与INT64_MAX,同样 abort。复现脚本
// aclnnDiag: diagonal=INT64_MIN 时 GetWorkspaceSize 直接 abort(期望 161002) // build: g++ -std=c++17 -O2 repro_diag.cpp -o repro_diag \ // -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 -lascendcl -lopapi -lnnopbase // run: ./repro_diag ctrl ; ./repro_diag defect #include <acl/acl.h> #include <aclnnop/aclnn_diag.h> #include <cstdint> #include <cstdio> #include <cstring> #include <vector> static aclTensor* mk(void* d, std::vector<int64_t> sh, aclDataType dt) { std::vector<int64_t> st(sh.size()); int64_t acc = 1; for (int i = (int)sh.size() - 1; i >= 0; --i) { st[i] = acc; acc *= (sh[i] ? sh[i] : 1); } return aclCreateTensor(sh.data(), sh.size(), dt, st.data(), 0, ACL_FORMAT_ND, sh.data(), sh.size(), d); } static void run(const char* tag, int64_t diag, std::vector<int64_t> outSh) { const int64_t n = 12; std::vector<int64_t> sh = {3, 4}; std::vector<float> h(n); for (int64_t i = 0; i < n; ++i) h[i] = (float)(i + 1); int64_t on = 1; for (auto v : outSh) on *= v; void *dIn = nullptr, *dOut = nullptr; aclrtMalloc(&dIn, n * 4, ACL_MEM_MALLOC_HUGE_FIRST); aclrtMalloc(&dOut, (size_t)(on > 0 ? on * 4 : 8), ACL_MEM_MALLOC_HUGE_FIRST); aclrtMemcpy(dIn, n * 4, h.data(), n * 4, ACL_MEMCPY_HOST_TO_DEVICE); aclTensor* self = mk(dIn, sh, ACL_FLOAT); aclTensor* out = mk(dOut, outSh, ACL_FLOAT); uint64_t ws = 0; aclOpExecutor* ex = nullptr; printf("%s diagonal=%lld -> ", tag, (long long)diag); fflush(stdout); int r = (int)aclnnDiagGetWorkspaceSize(self, diag, out, &ws, &ex); printf("ret=%d\n", r); aclDestroyTensor(self); aclDestroyTensor(out); aclrtFree(dIn); aclrtFree(dOut); } int main(int argc, char** argv) { aclInit(nullptr); aclrtSetDevice(0); if (argc > 1 && std::strcmp(argv[1], "ctrl") == 0) { run("[对照组 CTRL] diag=1(合法,out=[3])", 1, {3}); } else { run("[缺陷组 DEFECT] diag=INT64_MIN(越界,out=[0])", INT64_MIN, {0}); } aclFinalize(); return 0; }影响
diagonal常由外部参数/配置文件传入。任何批量取对角线、参数扫描或自动调优的调用方,一旦取到INT64_MIN(或 1 维输入下的INT64_MAX),调用进程直接退出而不是拿到错误码;在常驻服务里等价于一次拒绝服务。建议
op_api/aclnn_diag.cpp里三处有符号运算在极值下溢出,建议改为溢出安全写法并前置返回161002:-diagonal < rows与rows + diagonal用__builtin_sub_overflow/__builtin_add_overflow判定;diagonal == INT64_MIN时直接判非法。std::abs(diagonal)与inputShape.GetShapeSize() + std::abs(diagonal)同样做溢出检查。InferDiagOutShape之前,避免负维度下发到l0op::DiagV2的 tiling。