已关闭
[Bug-Report|缺陷反馈]: aclnnThreeInterpolateBackward A2 kernel 对 idx/weight 搬运长度未夹紧,合法输入即越界读(memcheck 16 处,96→180B) #1406
liuhanwen8创建于 12 天前关闭于 6 天前
liu-wei
12 天前 评论:
12 天前 评论:
您好,感谢反馈!
经过分析,问题属实:A2 kernel 对 idx/weight 的搬运长度固定为 N0 * 3 个元素,未按末循环实际 n 数量夹紧,单核 n 余量不足 N0=16 时即对输入张量产生越界读,与 memcheck 检出结果一致。
问题分析
问题位于 CopyIn(three_interpolate_backward.cpp#L261-L262):
DataCopy(idx_local, idx_gm[idx_addr_offset], N0 * 3);
DataCopy(weight_local, weight_gm[weight_addr_offset], N0 * 3);
- 搬运长度固定为
N0 * 3 = 48个元素。对比同一函数中grad_x的搬运(blockLen 取copy_in_last_loop_block_size,由core_last_loop_n_cnt按末循环 n 数夹紧,见 L140),idx/weight没有对应的夹紧逻辑;tiling 侧idx_move_block_size/weight_move_block_size也按满额3 * N0计算(three_interpolate_backward_tiling.cpp#L118-L119),UB 空间按满额分配,搬运会完整执行; - 以您的用例(
idx=int32[2x4x3],共 24 个元素 96 B)为例:n=4 < N0=16,各核仍按 48 个元素搬运,读取范围越过 96 B 的缓冲区,与 memcheck 在两个 96 B 基址上报出的 illegal_read 相符; - 越界读到的数据不参与有效计算(计算与写出环节均按
core_last_loop_n_cnt截断取值),因此计算结果正确,但构成对输入缓冲区的非法读,与您"合法输入、结果正常但 memcheck 报错"的观察一致。
后续计划
我们计划将 idx/weight 的搬运长度按末循环 n 数夹紧(对齐 32 B),消除对输入缓冲区的越界读;备注中提到的同 kernel initcheck 未初始化读问题,会在修复时一并排查确认是否同源。修复与回归用例将走评审流程合入,合入后会在本 issue 同步进展。感谢您提供完整的 memcheck 信息。


liuhanwen8
8 天前 评论:
8 天前 评论:
补充:A2 上可复现的最小脚本(NCHW 形态,memcheck 16 处 illegal read)
环境:Atlas A2(910B2,NPU4 / Health=OK)、CANN 9.2.0、g++ 11.4.0、aclnn 原生两段式直调(无 torch)。
ASCEND_RT_VISIBLE_DEVICES=4,单卡单进程。
注意:grad_x / grad_y 必须按 NCHW 创建;用 ACL_FORMAT_ND 时首段直接返回 561103。
#include <cstdio>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_three_interpolate_backward.h"
#define CK(x) do{auto _r=(x); if(_r!=0){printf("FAIL L%d ret=%d\n",__LINE__,(int)_r);return 2;}}while(0)
static aclTensor* mk(std::vector<int64_t> s, aclDataType d, void* p, aclFormat f){
std::vector<int64_t> st(s.size(),1);
for(int i=(int)s.size()-2;i>=0;--i) st[i]=s[i+1]*st[i+1];
return aclCreateTensor(s.data(),s.size(),d,st.data(),0,f,s.data(),s.size(),p);
}
static int run(const char* tag,int B,int Cc,int N,int M,int m,aclFormat f){
std::vector<float> hx(B*Cc*N,1.f), hw(B*N*M,0.3f);
std::vector<int32_t> hi(B*N*M);
for(size_t i=0;i<hi.size();++i) hi[i]=(int32_t)(i%m);
void *dx,*di,*dw,*dy;
CK(aclrtMalloc(&dx,B*Cc*N*4,ACL_MEM_MALLOC_HUGE_FIRST));
CK(aclrtMalloc(&di,B*N*M*4,ACL_MEM_MALLOC_HUGE_FIRST));
CK(aclrtMalloc(&dw,B*N*M*4,ACL_MEM_MALLOC_HUGE_FIRST));
CK(aclrtMalloc(&dy,B*Cc*m*4,ACL_MEM_MALLOC_HUGE_FIRST));
CK(aclrtMemcpy(dx,B*Cc*N*4,hx.data(),B*Cc*N*4,ACL_MEMCPY_HOST_TO_DEVICE));
CK(aclrtMemcpy(di,B*N*M*4,hi.data(),B*N*M*4,ACL_MEMCPY_HOST_TO_DEVICE));
CK(aclrtMemcpy(dw,B*N*M*4,hw.data(),B*N*M*4,ACL_MEMCPY_HOST_TO_DEVICE));
aclTensor *tx=mk({B,Cc,N,1},ACL_FLOAT,dx,f), *ti=mk({B,N,M},ACL_INT32,di,ACL_FORMAT_ND),
*tw=mk({B,N,M},ACL_FLOAT,dw,ACL_FORMAT_ND), *ty=mk({B,Cc,m,1},ACL_FLOAT,dy,f);
uint64_t ws=0; aclOpExecutor* ex=nullptr;
aclnnStatus r1=aclnnThreeInterpolateBackwardGetWorkspaceSize(tx,ti,tw,m,ty,&ws,&ex);
void* wp=nullptr; if(ws) CK(aclrtMalloc(&wp,ws,ACL_MEM_MALLOC_HUGE_FIRST));
aclrtStream st=nullptr; CK(aclrtCreateStream(&st));
aclnnStatus r2=(r1==0)?aclnnThreeInterpolateBackward(wp,ws,ex,st):(aclnnStatus)-1;
if(r2==0) CK(aclrtSynchronizeStream(st));
printf("TI[%s] B=%d C=%d N=%d M=%d m=%d ret1=%d ret2=%d ws=%llu\n",
tag,B,Cc,N,M,m,(int)r1,(int)r2,(unsigned long long)ws);
return 0;
}
int main(){
CK(aclInit(nullptr)); CK(aclrtSetDevice(0));
run("ND",2,3,4,3,6,ACL_FORMAT_ND);
run("NCHW",2,3,4,3,6,ACL_FORMAT_NCHW);
run("ND_small",1,1,1,3,4,ACL_FORMAT_ND);
return 0;
}
编译与运行
g++ -O2 repro.cpp -o repro -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 \
-lopapi -lascendcl -lnnopbase -lpthread
ASCEND_RT_VISIBLE_DEVICES=4 ./repro
mssanitizer -t memcheck --log-file mem.log -- ./repro
grep -c illegal mem.log
实测输出(本次复跑)
TI[ND] B=2 C=3 N=4 M=3 m=6 ret1=561103 ret2=-1 ws=0
TI[NCHW] B=2 C=3 N=4 M=3 m=6 ret1=0 ret2=0 ws=16779776
TI[ND_small] B=1 C=1 N=1 M=3 m=4 ret1=561103 ret2=-1 ws=0
(memcheck) illegal = 16, 全部落在 ThreeInterpolateBackward_fp32_int32_high_performance_0
结论:合法输入(idx 全部 ∈ [0,6))下两段 0/0,memcheck 检出 16 处 illegal read,全部在算子 kernel,与主体完全一致。


6 天前 关闭了 issue
6 天前 添加了label:resolved
现象
在完全合法的输入下(
idx取值全部落在[0, m)),msSanitizer memcheck 在算子 kernelThreeInterpolateBackward_fp32_int32_high_performance_0上检出 16 处 illegal_read。用例:
grad_x=fp32[2x3x4x1]NCHW、idx=int32[2x4x3]ND、weight=fp32[2x4x3]ND、m=6、grad_y=fp32[2x3x6x1]NCHWidx(24 × int32)与weight(24 × fp32),均为 96 B;实际读长度 96 → 180 B(步长 12 B = 3 个元素),最多超出缓冲区 84 B;
OnesLike/MatMulV2/TransData)只有寄存器复位警告,无 illegal_read,故定位在算子 kernel;
grad_x=fp32[1x1x1x1]NCHW、idx=(1,1,3)、grad_y=(1,1,4,1)另报 2 处(同 kernel)。复现
期望
idx/weight的搬运长度按实际张量大小夹紧(疑似 tiling 中each_core_proc_num/ n 的上界未夹紧),消除对输入缓冲区的越界读。
备注
同批 initcheck 在同一 kernel 另报未初始化读(UB 672 B、GM 96 B@
0x12c0c001a000等,共 27 处),推测与同一处长度计算相关,建议一并排查。