已关闭
[Bug-Report|缺陷反馈]: adump 模块存在 5 处共享变量无同步保护的并发缺陷 #1003
Lujialiang创建于 12 天前关闭于 4 天前
12 天前 添加了label:bug-report
Lujialiang
12 天前 评论:
12 天前 评论:
/assign


12 天前 将 Lujialiang 设为负责人
Lujialiang
12 天前 评论:
12 天前 评论:
/assign


11 天前 关联了pull request:fix: adump 模块存在 5 处共享变量无同步保护的并发缺陷 (#1003)
Lujialiang
11 天前 评论:
11 天前 评论:
修复 PR 已提交:https://gitcode.com/cann/runtime/merge_requests/5170
- 5 处共享变量并发缺陷修复(atomicIndex 原子化 / messageCallback_ 互斥 / g_dynamicChunk 析构策略 / dumpConfigInfo_ 快照 / dumpInitNum_ 原子+生命周期互斥)
- 新增 5 个并发 UT(tests/ut/adump),修复前确定性复现 bug24/bug28,修复后全绿
- 全量回归 1248/1248 PASSED(基线 1243 + 新增 5,零回归)
- pre-commit 门禁(clang-format v16 + OAT 合规)PASS
欢迎评审。


ykl999
4 天前 评论:
4 天前 评论:
pr已合入,issue问题已解决,关闭处理


4 天前 issue状态由 进行中 改变为 已解决
4 天前 关闭了 issue
4 天前 添加了label:resolved
Describe the current behavior / 问题描述
在
src/dfx/adump/adump/子系统复检确认 5 处并发缺陷:共享变量的并发读写缺乏互斥或原子保护,并发场景下可导致 dump 数据丢失、回调崩溃甚至进程崩溃。按严重性排序:1. dumpConfigInfo_ 跨锁读写(最严重)
manage/dump_manager/dump_manager.cpp:写侧SetDumpConfig(char*)持resourceMtx2_执行assign(:343),UnSetDumpConfig持resourceMtx2_执行clear(:379);读侧StartDumpArgs(:762)/StopDumpArgs(:782)在resourceMtx_内层作用域释放之后完全无锁读取.data()/.size()并传给模块回调。两把锁互不相交,assign触发重分配后回调收到悬垂指针 → UAF/OOB。2. dumpInitNum_ 多路径无公共锁 RMW
adx_dump_record.cpp:164-171裸int32_t++/--;四条访问路径锁互不相交:enable(dump_manager.cpp:279,持resourceMtx_)、disable(:387,持resourceMtx2_)、快照 LOCK_PRE 回调(:86-90,完全无锁,RTS 快照线程)、算子捕获路径(:579,无锁,另有isCaptureDumpServerInit_裸 bool check-then-act :578-580)。计数漂移 → DataDumpServer 过早关闭(dump 数据静默丢失)或无法关闭(线程泄漏)。3. messageCallback_ 无锁 std::function 读写
adx_dump_process.cpp:Register(:20)/UnRegister(:38)无锁写;GetCallbackFun(:24)返回 const 引用,record 长驻线程(adx_dump_record.cpp:571/:728)无锁拷贝后调用。acldumpRegCallback/acldumpUnregCallback为公开 AscendCL API(host/adx_datadump_callback.cpp),运行期可调;UnRegister 的= nullptr销毁 function 目标,与 record 线程拷贝并发 → 撕裂的 function 对象 → 调用野指针崩溃。4. g_dynamicChunk 析构窗口 UAF
exception/exception_dumper.cpp:~ExceptionDumper(:70-72)无锁delete[]之后才置destructionFlag_(:80),且该标志仅在DumpException入口(:174)检查;导出 APIAdxGetDFXInfoAddrForDynamic(manage/adump_api.cpp:27,无锁读写 chunk)与异常回调DfxArgsParser::GetShapeData(exception/dfx_args_parser.cpp:191,无锁读)均不检查 → 进程收尾/dlclose 期间并发访问已释放 chunk(约 3MB)→ UAF 写。5. g_atomicIndex 非原子 RMW
manage/adump_api_platform.cpp:25/:138:裸uint32_t++,同函数紧邻的:139姊妹变量g_writeIdx已用std::atomic::fetch_add(原子/非原子不对称,属遗漏)。AdumpGetSizeInfoAddr为extern "C" ADX_API导出接口,并发调用丢失自增 → 两个调用方拿到相同atomicIndex→ dump 元数据关联错乱。孪生代码adump_ascend031/manage/adump_api_platform.cpp:20/:29同款。Environment / 环境信息
e781819e6,2026-09 复核);上述行号均锚定该版本,2026-08 版本(0029b34a0)同样存在Steps to reproduce the issue / 重现步骤
并发时序场景(ThreadSanitizer 可直接检出,以下任一即可):
aclopStartDumpArgs(触发模块回调读取dumpConfigInfo_)∥ 线程 B 调 dump 配置更新(SetDumpConfig/UnSetDumpConfig的 assign/clear)→ A 的回调收到 B 重分配前的悬垂指针SetDumpConfig→StartDataDumpServer)∥ 快照备份触发 LOCK_PRE 回调(StopDataDumpServer循环 UnInit)→dumpInitNum_丢失更新acldumpUnregCallback→ 拷贝到一半的 std::function~ExceptionDumper(delete[] chunk)∥ 残留线程调AdxGetDFXInfoAddrForDynamic或异常回调读 chunk → 对已释放内存写入AdumpGetSizeInfoAddr→++丢失更新 → 相同 atomicIndexDescribe the expected behavior / 预期结果
std::atomic),ThreadSanitizer 无告警dumpInitNum_在 enable/disable/快照并发下计数准确,DataDumpServer 不被过早关闭或泄漏AdumpGetSizeInfoAddr并发调用返回唯一 atomicIndexRelated log / screenshot / 日志 / 截图
暂无运行时崩溃日志(竞态窗口窄,尚未在现网触发)。源码证据已在问题描述中逐条标注 file:line(基于 commit
e781819e6)。如需可补充每个缺陷的最小化并发复现用例。Special notes for this issue/备注
dumpInitNum_完整修复(含 check-then-act 消解)约 30-40 行;无架构级改动dumpConfigInfo_:读侧在resourceMtx_释放后、回调前,持resourceMtx2_拷贝快照再传给回调(注意写侧存在 Mtx2_→Mtx_ 嵌套,锁序不可反转)dumpInitNum_:改std::atomic<int32_t>,并用fetch_add返回值替代CanShutdownServer/HasStartedServer的 check-then-act 判定messageCallback_:加 mutex;GetCallbackFun持锁返回值拷贝(调用点本就以局部变量承接,无需改动)g_dynamicChunk:收尾不 delete(进程级单例内存交 OS 回收),或destructionFlag_提前置位 + atomic + 导出 API 检查g_atomicIndex:改std::atomic<uint32_t>+fetch_add(与同函数g_writeIdx风格统一)