Closed
[Bug-Report|缺陷反馈][工具检测]: matmul_a2b2_shareisA2B2Shared 模式下 InitShareBufEnd 条件跳过导致 PRIVATE 未初始化读 + IterateAll 尾部越界导致 GM 非法读写,mssanitizer memcheck/initcheck 报 603 条错误 #1678
h-glueAdd on  Sep 16Closed at  Sep 28
h-glue
Sep 16 Create

问题描述 (Mandatory / 必填)

在 asc-devkit 示例 examples/01_simd_cpp_api/04_advanced_api/00_matmul/matmul_a2b2_share 上启用 mssanitizer(memcheck/racecheck/initcheck/synccheck)检测,共报告 603 条错误,可归为以下三类:

错误类别 错误类型 数量 范围
GM 非法读 illegal read of size 128 (GM) 150 仅 aic(26)
GM 非法写 illegal write of size 1024/896 (GM) 60 (30×1024 + 30×896) 仅 aic(26)
PRIVATE 未初始化读 uninitialized read of size 8 (PRIVATE) 243 aic(0)~aic(26) 全部核
GM 未初始化读 uninitialized read of size 128 (GM) 150 仅 aic(26)
合计 603 serialNo: 282~158592

关键特征:

  1. GM 非法读写只发生在 aic(26)(最后一个核),其余核(aic 0~25)均无 GM 越界;
  2. 两个 matmul 对象均受影响:matmulObj1.IterateAll(c1Global)(.asc 第 135 行)与 matmulObj2.IterateAll(c2Global)(第 137 行);
  3. 非法读地址精确落在 A 缓冲区结束地址处:a1 结束 0x1201a1AB0000、a2 结束 0x1201a20B0000;
  4. 非法写地址精确落在 C 缓冲区结束地址处:c1 结束 0x1201a3010000、c2 结束 0x1201a4010000;
  5. PRIVATE 未初始化读出现在 全部 27 个核(aic 0~26),根因与 HasScalePosition<half>::value = true 导致 InitShareBufEnd 被条件跳过相关:
    • 第一个错误(serialNo:282)调用栈指向 scheduler_base.h:139 的 InitShareBufEnd 调用点 —— HasScalePosition<half> 为 true 时该调用被 if constexpr 跳过,L0A/L0B 缓冲区 maxAddr 未恢复;
    • 第二个错误(serialNo:477)调用栈指向 load_bias_to_c2.h:81 —— 偏置加载使用了错误的地址(因 maxAddr 未正确恢复);
    • 第三个错误(serialNo:497)调用栈指向 tbuf_pool_l0_a2b2_shared.h:52 —— A2B2 双缓冲标志 WaitFlag 等待混乱;
  6. GM 未初始化读(150 条,size 128)与 GM 非法读(150 条,size 128)共享完全相同的调用栈路径 copy_cube_in 阶段,是同源错误的一体两面。

环境信息 (Mandatory / 必填)

项 值
硬件型号 Atlas 950(dav-3510)
代码分支 asc-devkit 9.1.0 分支
软件版本 CANN 9.1.0
工具链 Ascend C(ascendc-bin 编译),mssanitizer(MindStudio Sanitizer)memcheck + initcheck
算子示例 examples/01_simd_cpp_api/04_advanced_api/00_matmul/matmul_a2b2_share
运行模式 NPU(CMAKE_ASC_RUN_MODE=npu),CMAKE_ASC_ARCHITECTURES=dav-3510

重现步骤 (Mandatory / 必填)

  1. 拉取 asc-devkit 并切到 9.1.0 分支,进入示例目录:
cd examples/01_simd_cpp_api/04_advanced_api/00_matmul/matmul_a2b2_share
  1. 编译(950 平台):
mkdir -p build && cd build
export ASCFLAGS= "-g --cce-enable-sanitizer"
cmake -DSCENARIO_NUM=1 -DCMAKE_ASC_ARCHITECTURES=dav-3510 -DCMAKE_ASC_LINK_FLAGS=--cce-enable-sanitizer ..
make
  1. 生成输入数据:
python3 ../scripts/gen_data.py
  1. 启用 mssanitizer 运行(算子关键配置见 matmul_a2b2_share.asc 中 isA2B2Shared = true,形状 M=7680, N=480, K=320,half 输入、float 输出、带 bias):
# 通过 MindStudio 运行,启用 --cce-enable-sanitizer=memcheck,racecheck,initcheck,synccheck
./demo

mssanitizer  -t initcheck  --log-level=error --full-backtrace=yes -- ./demo
  1. 观察日志输出:
    • aic(0)~aic(26) 全核均上报 PRIVATE uninitialized read(serialNo:282 起);
    • aic(26) 单独上报 GM illegal read/write + GM uninitialized read(serialNo:154697 起)。

预期结果 (Mandatory / 必填)

mssanitizer 检测不应报告任何错误。具体地:

  1. 对于 PRIVATE 未初始化读:HasScalePosition<half> 为 true 时,InitShareBufEnd 不应被跳过 —— L0A/L0B 缓冲区的 maxAddr 应正确恢复,偏置加载和 A2B2 双缓冲标志应正常工作;
  2. 对于 GM 非法读写:Matmul 库在 isA2B2Shared = true 模式下,IterateAll 对最后一个核的最后一个分块应正确做边界截断,不应发生越过 GM 缓冲区尾部的非法读(A 矩阵尾部)与非法写(C 矩阵尾部)。

相关日志/截图 (Mandatory / 必填)

完整日志文件:result_fix/matmul_a2b2_share/san.log(~1.5 MB,603 条错误)

错误 1:PRIVATE uninitialized read(serialNo:282,全部 27 个核)—— InitShareBufEnd 被条件跳过:

====== ERROR: uninitialized read of size 8
======    at 0x7690 on PRIVATE in "matmul_a2b2_share_custom(...)"
======    in block aic(0) on device 0
======    code in pc current 0x12dc (serialNo:282)
======    #0 /.../kernel_tpipe_impl_c310.h:0:23
======    #1 /.../scheduler_base.h:139:13   <-- InitShareBufEnd 调用点,因 HasScalePosition<half>::value=true 被 if constexpr 跳过
======    #2 /.../matmul_impl_base.h:435:31
======    #3 /.../kfc_register_obj.h:142:11
======    #4 /.../kfc_register_obj.h:130:5
======    #5 /.../kfc_register_obj.h:144:13
======    #6 matmul_a2b2_share.asc:170:5   <-- REGIST_MATMUL_OBJ

错误 2:PRIVATE uninitialized read(serialNo:477,全部 27 个核)—— 偏置加载地址错误:

====== ERROR: uninitialized read of size 8
======    at 0x7688 on PRIVATE in "matmul_a2b2_share_custom(...)"
======    in block aic(0) on device 0
======    code in pc current 0x2390 (serialNo:477)
======    #0 /.../kernel_operator_data_copy_impl.h:0:13
======    #1 /.../kernel_operator_data_copy_impl.h:841:5
======    #2 /.../kernel_operator_data_copy_intf_impl.h:389:13
======    #3 /.../load_bias_to_c2.h:81:13   <-- DataCopy(biasC2, bias, ...) 使用未初始化地址
======    #4 /.../bias_scheduler_v220.h:123:41
======    #5 /.../scheduler_norm_base.h:393:39
======    #6 /.../scheduler_norm.h:223:26
======    #7 /.../scheduler_norm.h:147:13
...
======   #11 matmul_a2b2_share.asc:135:16   <-- matmulObj1.IterateAll(c1Global)
======   #12 matmul_a2b2_share.asc:173:18   <-- matmulKernel.Process()

错误 3:GM illegal read(serialNo:154697,仅 aic(26))—— copy_cube_in 尾部越界:

====== ERROR: illegal read of size 128
======    at 0x1201a1ab0a00 on GM in "matmul_a2b2_share_custom(...)"
======    in block aic(26) on device 0
======    code in pc current 0x1d10 (serialNo:154697)
======    #0 /.../kernel_operator_data_copy_impl.h:323:13
======    #1 /.../kernel_operator_data_copy_impl.h:354:9
======    #2 /.../kernel_operator_data_copy_intf_impl.h:141:9
======    #3 /.../data_copy_wrapper_nd.h:124:9
======    #4 /.../copy_tile_to_cube_common.h:471:23
======    #5 /.../copy_tile_to_cube_common.h:112:21
======    #6 /.../copy_cube_in_norm.h:101:56
======    #7 /.../scheduler_norm.h:206:23
======    #8 /.../scheduler_norm.h:147:13
======    #9 /.../scheduler_norm.h:133:9
======   #10 /.../matmul_impl_base.h:720:38
======   #11 /.../matmul_impl.h:133:37
======   #12 matmul_a2b2_share.asc:135:16   <-- matmulObj1.IterateAll(c1Global)
======   #13 matmul_a2b2_share.asc:173:18   <-- matmulKernel.Process()

错误 4:GM illegal write(serialNo:155243,仅 aic(26))—— copy_cube_out 尾部越界:

====== ERROR: illegal write of size 1024
======    at 0x1201a3014b00 on GM in "matmul_a2b2_share_custom(...)"
======    in block aic(26) on device 0
======    code in pc current 0x14e0 (serialNo:155243)
======    #0 /.../kernel_operator_fixpipe_impl.h:326:12
======    #1 /.../kernel_operator_fixpipe_impl.h:663:9
======    #2 /.../kernel_operator_fixpipe_intf_impl.h:244:5
======    #3 /.../copy_cube_out_utils.h:155:17
======    #4 /.../copy_cube_out_fixpipe.h:340:30
======    #5 /.../copy_cube_out_fixpipe.h:185:9
======    #6 /.../copy_cube_out_fixpipe.h:110:13
======    #7 /.../copy_cube_out_fixpipe.h:78:13
======    #8 /.../scheduler_base.h:501:28
======    #9 /.../scheduler_base.h:212:9
======   #10 /.../matmul_impl_base.h:695:31
======   #11 /.../matmul_impl.h:134:34
======   #12 matmul_a2b2_share.asc:135:16   <-- matmulObj1.IterateAll(c1Global)
======   #13 matmul_a2b2_share.asc:173:18   <-- matmulKernel.Process()

地址映射分析(基于 a1/acl MALLOC 基址 0x1201a1600000 与缓冲区大小推算):

缓冲区 基址 结束地址 错误类型 越界起始地址 越界大小
a1 0x1201a1600000 0x1201a1AB0000 illegal read 128B 0x1201a1AB0000 ~8,960 B
a2 0x1201a1C00000 0x1201a20B0000 illegal read 128B 0x1201a20B0000 ~8,960 B
c1 0x1201a2200000 0x1201a3010000 illegal write 1024B/896B 0x1201a3010000 ~28,032 B
c2 0x1201a3200000 0x1201a4010000 illegal write 1024B/896B 0x1201a4010000 ~28,032 B

注:a1/a2 缓冲区大小 = M×K×sizeof(half) = 7680×320×2 = 4,915,200 B;c1/c2 缓冲区大小 = M×N×sizeof(float) = 7680×480×4 = 14,745,600 B。地址块之间的 0x150000(~1.3 MB)间隙为 ACL 硬件对齐填充,未被映射为合法内存。


备注 (Optional / 选填)

  • 两类错误同源关联分析:

    • PRIVATE uninitialized read(243 条)的问题是 HasScalePosition<half> 类型检测 trait 在 half 上返回 true,导致 scheduler_base.h:138-139 中 if constexpr (!HasScalePosition<A_TYPE>::value) { InitShareBufEnd(...); } 被编译期跳过。这导致 L0A/L0B 共享缓冲区 maxAddr 在第二个 matmul 对象初始化时未正确恢复,进而偏置加载地址和 A2B2 双缓冲标志出现未初始化读。但该问题影响所有核且表现为 PRIVATE 空间错误,不直接导致 GM 越界。
    • GM illegal read/write(210 条)与 GM uninitialized read(150 条)是 尾部 last-tile 越界问题,仅影响最后一个核 aic(26)。copy_cube_in 以固定 vector 长度(128B)从 GM 读取 A 分块时未对最后一个分块做边界截断,读入了缓冲区尾部缝隙,同时也解释了同地址的 GM 未初始化读。
  • 上述两类错误相互独立:PRIVATE uninit 是库调度逻辑缺陷(InitShareBufEnd 条件跳过),GM 越界是迭代器边界缺陷(last tile 截断缺失)。但两者在 isA2B2Shared = true 模式下同时触发,建议库侧分别排查:

    1. scheduler_base.h:138 —— 将 HasScalePosition 检查逻辑修正,确保 half 类型下 InitShareBufEnd 仍被调用;
    2. copy_tile_to_cube_common.h:471 / scheduler_norm.h:206 —— 在 IterateAll 最后一次迭代中对尾部 tile 做 GM 边界截断。
  • 当前功能正确性:scripts/verify_result.py 校验通过(输出与 golden 一致)。越界读写的目标地址落在缓冲区之间 ACL 硬件对齐填充的空闲缝隙中,未造成实际数据破坏,但技术上属不安全访问。

  • 对照验证:将 GetCustomCFG() 中 isA2B2Shared 设为 false(即退回 CFG_NORM)后重新运行,GM 非法读写清零,PRIVATE 未初始化读亦消失,进一步印证上述分析。

likedislike
Hh-glue
Sep 16 Modify description of issue
Hh-glue
Sep 16 Modify description of issue
Hh-glue
Sep 16 Change title to "[Bug-Report|缺陷反馈][工具检测]: matmul_a2b2_shareisA2B2Shared 模式下 InitShareBufEnd 条件跳过导致 PRIVATE 未初始化读 + IterateAll 尾部越界导致 GM 非法读写,mssanitizer memcheck/initcheck 报 603 条错误", originally titled "[Bug-Report|缺陷反馈]: matmul_a2b2_shareisA2B2Shared 模式下 InitShareBufEnd 条件跳过导致 PRIVATE 未初始化读 + IterateAll 尾部越界导致 GM 非法读写,mssanitizer memcheck/initcheck 报 603 条错误".
Lli-yuanjie-daCollaborators
Sep 16 Assign li-yuanjie-da as responsible person
li-yuanjie-daCollaborators
Sep 16 Comments:

感谢补充完整分类及关闭isA2B2Shared的对照结果。静态核对发现,普通half输入使用的MatmulType不含scalePosition,因此不能据此认定InitShareBufEnd被跳过;该函数也不负责恢复 L0A/L0B maxAddr。我们将结合对应地址的实际读写指令、对象初始化状态和950上的对照日志进一步定位。

likedislike
Kkong0808Collaborators
Sep 24 Removed responsible person li-yuanjie-da
Kkong0808Collaborators
Sep 24 Assign hyolee as responsible person
Kkong0808Collaborators
Sep 24 Assign ca1kw as responsible person
ca1kw
ca1kwCollaborators
Sep 28 Comments:

您好,对于该Issue中GM 非法读、GM 非法写和 GM 未初始化读已由关联pr进行修复。修复方式是在尾部核上按实际剩余的 M/N/K 长度调用 SetTail(),避免 Matmul 调度器按完整 tile 长度继续访问 GM。

验证结果:

  • mssanitizer -t memcheck:0 error
  • verify_result.py:test pass!
  • 原 GM 非法读、GM 非法写、GM 未初始化读均已消除

对于当前 initcheck 仍剩余 216 条 PRIVATE 未初始化读,较原始 PRIVATE 报错数 243 条减少 27 条。剩余报错均来自 CANN 内部状态,不是样例侧 GM 访问逻辑问题:

数量 对应状态 说明
27 Internal::g_bufId TPipe::ResetPool() 已执行 g_bufId = 0,但 initcheck 仍报未初始化,疑似工具未正确跟踪该写入
135 gA2B2DBFlag_ CANN A2B2 共享实现内部的 __BLOCK_LOCAL__ 状态,首次读取前没有显式运行时写入。initcheck 的判定原理是读取某地址时检查该地址是否已被写过;如果之前没有写入,工具无法将其视为已初始化,也不能替业务补写。由于 __BLOCK_LOCAL__ 变量不支持声明时赋初始值,不能通过 gA2B2DBFlag_ = 0 的静态初始化方式规避,需 CANN/库侧在首次读取前提供合法的运行时初始化路径
54 TPipe 内部 eventPool_ 状态 TPipe::ResetPool() 已遍历清零事件池,但 initcheck 仍报未初始化,说明工具对构造/Reset 阶段的写跟踪不完整

综上,本 issue 中的 GM 越界问题已解决;剩余 initcheck PRIVATE 报错建议转由 mssanitizer / CANN 内部实现侧继续排查,不建议在当前样例中通过强行初始化内部状态规避。

likedislike
Hh-glue
Sep 28 changed custom state from 待办的 to 已解决
Hh-glue
Sep 28 Close issue
CANN-robotCANN-robotCollaborators
Sep 28 Added label: resolved