您好,感谢反馈!按您报告的 cann/ops-math@584b2ea6cbaeba684a51a74296d82d4d50ab3b0f 核查,IsInf 尾块实现确实把输入、输出的 GM 搬运长度向 32 字节边界扩展,能够解释您给出的尾部字节数。
问题分析
这里输入按 int16_t 单元访问,输出按 uint8_t 单元访问,CopyInX/CopyOut直接把传入长度交给 DataCopy。以一个 FLOAT 元素为例:有效输入是 4 字节,对应 2 个 int16 单元;尾块上取整为 16 个 int16 单元后读取 32 字节,超过有效输入 28 字节。输出的有效 BOOL 长度为 1 字节,却再次上取整为 32 字节,超过有效输出 31 字节。numel=7/15 时输出多搬运 25/17 字节,也与报告一致。
需要分清有效长度与分配长度:您当前探针给输出实际分配了 64 字节,哨兵变化直接证明的是逻辑输出区外被写;超过真实分配边界的访问则对应您报告的 memcheck 结果。复验还应结合实际缓冲映射和分配边界确认,不能因为探针预留了空间就忽略整图复用或相邻有效区域的风险。IsNegInf 在这组对照中没有同样改写,是有用的定位线索,但不代表两个接口共用同一尾块实现。
处理方向
一个可行方案是把 GM 的真实尾部读写长度与 UB 的对齐计算长度分开:输入只搬入有效字节,在 UB 内完成必要填充和向量对齐;输出只搬回真实 BOOL 元素数。可评估使用支持精确尾长的搬运方式,如适用的 DataCopyPad,并核对输入、输出两侧长度单位。仅删除两处上取整、仍沿用普通整块 DataCopy,可能无法完成未对齐尾部的正确搬运。
验证可覆盖 numel=1/7/15/31/32/33、多核最后尾块以及不同输入精度,同时检查数值、哨兵区和 memcheck。当前提交中未定位到 IsInf 公开第一段的完整包装实现,API 输出与内核缓冲的对应仍需结合目标库核实;以上为内核及 tiling 源码核对,尚未独立设备实测。我们会继续确认尾块搬运的有效范围及修正方式。


现象
aclnnIsInf尾块按 32 字节整块搬运,越过out的实际大小,造成 GM 越界写/读;同形aclnnIsNegInf无此问题。illegal read of size 28/illegal write of size 31,与上面字节数吻合。期望
out只允许写numel字节(aclTensor 的逻辑大小);尾块按实际元素数搬运,不得整块 32B 读写。环境
soc=Ascend910B2)584b2ea6复现步骤
math/is_inf/op_api/aclnn_is_inf.h与math/is_neg_inf/op_api/aclnn_isneginf.h;库用 CANN 的libopapi.so/libnnopbase.so/libascendcl.so。repro:out缓冲分配 64 字节并整体预填0xAA,aclTensor 逻辑大小仍是numel字节。./repro 0,程序统计[numel, 64)内被改写的字节数。复现脚本
g++ -std=c++17 -O1 repro.cpp -o repro \ -I$ASCEND_HOME/include -I$ASCEND_HOME/aarch64-linux/include/aclnnop \ -I<ops-math>/math/is_inf/op_api -I<ops-math>/math/is_neg_inf/op_api \ -I<ops-math>/common/inc/external -I<ops-math>/third_party/opbase/include \ -L$ASCEND_HOME/lib64 -lopapi -lnnopbase -lascendcl LD_LIBRARY_PATH=$ASCEND_HOME/lib64 ./repro 0// aclnnIsInf 越界写探针:out 逻辑大小 n 字节,缓冲分配 64B 并预填 0xAA #include <acl/acl.h> #include <cstdio> #include <cstdlib> #include <vector> #include "aclnn_is_inf.h" #include "aclnn_isneginf.h" static void probe(const char* name, bool isInf, int64_t n) { const size_t BUF = 64; void *xDev = nullptr, *oDev = nullptr; aclrtMalloc(&xDev, n * sizeof(float), ACL_MEM_MALLOC_HUGE_FIRST); aclrtMalloc(&oDev, BUF, ACL_MEM_MALLOC_HUGE_FIRST); std::vector<float> hx(n, 1.0f); aclrtMemcpy(xDev, n * sizeof(float), hx.data(), n * sizeof(float), ACL_MEMCPY_HOST_TO_DEVICE); std::vector<unsigned char> canary(BUF, 0xAA); aclrtMemcpy(oDev, BUF, canary.data(), BUF, ACL_MEMCPY_HOST_TO_DEVICE); std::vector<int64_t> d{n}, s{1}; aclTensor* x = aclCreateTensor(d.data(), 1, ACL_FLOAT, s.data(), 0, ACL_FORMAT_ND, d.data(), 1, xDev); aclTensor* out = aclCreateTensor(d.data(), 1, ACL_BOOL, s.data(), 0, ACL_FORMAT_ND, d.data(), 1, oDev); aclrtStream st = nullptr; aclrtCreateStream(&st); uint64_t ws = 0; aclOpExecutor* ex = nullptr; aclnnStatus r1 = isInf ? aclnnIsInfGetWorkspaceSize(x, out, &ws, &ex) : aclnnIsNegInfGetWorkspaceSize(x, out, &ws, &ex); int r2 = -1; if (r1 == ACL_SUCCESS) { void* wsp = nullptr; if (ws > 0) { aclrtMalloc(&wsp, ws, ACL_MEM_MALLOC_HUGE_FIRST); } r2 = static_cast<int>(isInf ? aclnnIsInf(wsp, ws, ex, st) : aclnnIsNegInf(wsp, ws, ex, st)); aclrtSynchronizeStream(st); if (wsp != nullptr) { aclrtFree(wsp); } } std::vector<unsigned char> back(BUF, 0); aclrtMemcpy(back.data(), BUF, oDev, BUF, ACL_MEMCPY_DEVICE_TO_HOST); int outside = 0; for (size_t i = static_cast<size_t>(n); i < BUF; ++i) { if (back[i] != 0xAA) { ++outside; } } printf("%-9s numel=%-3lld ret1=%d ret2=%d | 越界改写字节数=%d\n", name, static_cast<long long>(n), static_cast<int>(r1), r2, outside); fflush(stdout); aclDestroyTensor(x); aclDestroyTensor(out); aclrtFree(xDev); aclrtFree(oDev); aclrtDestroyStream(st); } int main(int argc, char** argv) { int dev = (argc > 1) ? atoi(argv[1]) : 0; aclInit(nullptr); aclrtSetDevice(dev); probe("IsInf", true, 1); probe("IsInf", true, 7); probe("IsNegInf", false, 1); probe("IsNegInf", false, 7); aclrtResetDevice(dev); aclFinalize(); return 0; }实测输出:
影响
整图执行时
out只有numel字节,多写的字节落在相邻 tensor / workspace 上:numel 不是 32 整数倍的用例会静默踩坏其它张量,表现为随机精度异常或后段 coredump,报错点与真正出错的算子不一致。memcheck 在自动化路径两轮均复现,同形 IsNegInf 两轮全绿。建议
math/is_inf/op_kernel/is_inf.h的ComputePerCore()尾块里,输出侧actualOutCount = CeilAlign(actualOutCount, DATA_BLOCK)把搬运长度抬到 32 字节,输入侧dataCount = CeilAlign(tailDataCount, dataBlock)同样按块上取整。建议尾块改用DataCopyPad或按tailDataCount的真实字节搬运,去掉这两处DATA_BLOCK对齐,并补 numel=1/7/15 的 ST + memcheck。