已关闭
[Bug-Report|缺陷反馈]: alltoallv通信缺陷 #113
issuebot创建于  5月15日关闭于  5月25日
issuebot
5月15日 创建

AllToAllV 代码检视报告(详细版)

检视模块src/ops/all_to_all_v/
检视模式:条款级精确检视


1. 检视概览

统计项 数值
检视条款数 6 条
发现问题总数 17 个
高风险问题 14 个
中风险问题 3 个

问题分布

数值安全问题   ████████████ 6个 (35%)
内存安全问题   ████████████ 8个 (47%)
并发安全问题   ████████     3个 (18%)

2. 无符号整数运算不回绕

检视结果FAIL | 置信度:HIGH (85%)

问题1:乘法运算无溢出保护

文件src/ops/all_to_all_v/selector/alltoall_auto_selector.cc
行号:67-68, 114-115

问题代码

67: uint32_t dataTypeSize = DATATYPE_SIZE_TABLE[opParam.all2AllDataDes.sendType];
68: uint64_t dataSize = opParam.all2AllDataDes.sendCount * dataTypeSize;

问题描述

  • sendCountdataTypeSize 都是 uint 类型
  • 乘法运算可能溢出回绕
  • 导致数据量计算错误,可能内存分配不足或访问越界

修复建议

uint32_t dataTypeSize = DATATYPE_SIZE_TABLE[opParam.all2AllDataDes.sendType];
if (dataTypeSize == 0 || opParam.all2AllDataDes.sendCount == 0) {
    HCCL_ERROR("dataTypeSize or sendCount is zero");
    return HCCL_E_PARA;
}
if (opParam.all2AllDataDes.sendCount > UINT64_MAX / dataTypeSize) {
    HCCL_ERROR("dataSize overflow detected");
    return HCCL_E_PARA;
}
uint64_t dataSize = opParam.all2AllDataDes.sendCount * dataTypeSize;

问题2:计算偏移无溢出保护

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:161-164

问题代码

161: u64 curSendCounts = *(static_cast<const u64 *>(param.all2AllVDataDes.sendCounts) + j);
162: u64 curSendDispls = *(static_cast<const u64 *>(param.all2AllVDataDes.sdispls) + j);
163: localSendRecvInfo_.sendCounts[j] = curSendCounts;
164: localSendRecvInfo_.sendDispls[j] = curSendDispls;

问题描述

  • 直接使用外部数据进行偏移计算
  • 未检查 curSendDispls 是否会导致地址计算溢出

修复建议

u64 curSendCounts = *(static_cast<const u64 *>(param.all2AllVDataDes.sendCounts) + j);
u64 curSendDispls = *(static_cast<const u64 *>(param.all2AllVDataDes.sdispls) + j);
// 检查偏移值是否合理
if (curSendDispls + curSendCounts > param.inputSize) {
    HCCL_ERROR("sendDispls + sendCounts exceeds inputSize");
    return HCCL_E_PARA;
}
localSendRecvInfo_.sendCounts[j] = curSendCounts;
localSendRecvInfo_.sendDispls[j] = curSendDispls;

问题3:数据大小计算无保护

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:305-307

问题代码

305: tempAlgParams.inputSliceStride = maxDataCountPerLoop * dataTypeSize_;
306: // 这里用来放每张卡之间的stride大小
307: tempAlgParams.outputSliceStride = maxSendOrRecvDataCount * dataTypeSize_;

问题描述

  • 多处乘法运算未检查溢出
  • maxDataCountPerLoop * dataTypeSize_ 可能溢出

修复建议

if (dataTypeSize_ == 0) {
    HCCL_ERROR("dataTypeSize_ is zero");
    return HCCL_E_PARA;
}
if (maxDataCountPerLoop > UINT64_MAX / dataTypeSize_) {
    HCCL_ERROR("inputSliceStride overflow");
    return HCCL_E_PARA;
}
tempAlgParams.inputSliceStride = maxDataCountPerLoop * dataTypeSize_;

3. 除法/余数运算除零保护

检视结果FAIL | 置信度:HIGH (90%)

问题1:除法运算除零风险

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:282-284

问题代码

282: u64 maxDataCountPerLoop = maxDataSizePerLoop / dataTypeSize_; // 发往单卡的数据count
283: if (param.engine == CommEngine::COMM_ENGINE_AIV) {
284:     maxDataCountPerLoop = maxDataCountPerLoop / rankSize_;

问题描述

  • 两处除法运算,均未检查除数是否为0
  • dataTypeSize_rankSize_ 均可能为0
  • 除零错误会导致程序崩溃

修复建议

if (dataTypeSize_ == 0) {
    HCCL_ERROR("dataTypeSize_ is zero, cannot divide");
    return HCCL_E_PARA;
}
u64 maxDataCountPerLoop = maxDataSizePerLoop / dataTypeSize_;
if (param.engine == CommEngine::COMM_ENGINE_AIV) {
    if (rankSize_ == 0) {
        HCCL_ERROR("rankSize_ is zero, cannot divide");
        return HCCL_E_PARA;
    }
    maxDataCountPerLoop = maxDataCountPerLoop / rankSize_;
}

问题2:切分算法除零风险

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_concurrent_executor.cc
行号:115-117, 143

问题代码

115: uint32_t factorMesh = rankSize_ - 1;
116: uint32_t factorClos = CONST_4;
117: uint32_t factor = factorMesh + factorClos;
143: sendRecvInfoFirst.sendCounts[i] = localSendRecvInfo_.sendCounts[i] / factor * factorClos;

问题描述

  • 未检查 factor 是否为0
  • rankSize_ == 1 时,factorMesh = 0,但 factor = CONST_4 = 4,不会除零
  • 但如果代码逻辑变更可能导致除零风险

修复建议

uint32_t factor = factorMesh + factorClos;
if (factor == 0) {
    HCCL_ERROR("factor is zero, cannot divide");
    return HCCL_E_PARA;
}
sendRecvInfoFirst.sendCounts[i] = localSendRecvInfo_.sendCounts[i] / factor * factorClos;

问题3:循环计算除零

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:301-302

问题代码

301: u64 loopTimes = maxSendOrRecvDataCount / maxDataCountPerLoop +
302:     static_cast<u64>(maxSendOrRecvDataCount % maxDataCountPerLoop != 0);

问题描述

  • 未检查 maxDataCountPerLoop 是否为0
  • 第290行有检查 maxDataCountPerLoop == 0,但防御不完整

修复建议

if (maxDataCountPerLoop == 0) {
    HCCL_ERROR("maxDataCountPerLoop is zero");
    return HCCL_E_PARA;
}
u64 loopTimes = maxSendOrRecvDataCount / maxDataCountPerLoop +
    static_cast<u64>(maxSendOrRecvDataCount % maxDataCountPerLoop != 0);

4. 数组索引校验

检视结果FAIL | 置信度:HIGH (95%)

问题1:访问 infos[0] 未检查边界

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:56-59, 69-79

问题代码

56: if (algHierarchyInfo.infos.size() == 0) {
57:     HCCL_ERROR("algHierarchyInfo level num is zero!");
58:     return HCCL_E_PARA;
59: }
...
69: tempAlgHierachyInfo.push_back(algHierarchyInfo.infos[0][1]);

问题描述

  • 检查了 infos.size() == 0
  • 但未检查 infos[0].size() >= 2
  • 直接访问 infos[0][1] 可能越界

修复建议

if (algHierarchyInfo.infos.size() == 0 || algHierarchyInfo.infos[0].size() < 2) {
    HCCL_ERROR("algHierarchyInfo.infos size invalid");
    return HCCL_E_PARA;
}
tempAlgHierachyInfo.push_back(algHierarchyInfo.infos[0][1]);

问题2:访问 infos[0] 和 infos[1] 未检查

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:71-78

问题代码

71: CHK_PRT_RET(algHierarchyInfo.infos[0][1].size() >= algHierarchyInfo.infos[1][0].size(),
72:              HCCL_ERROR("..."), algHierarchyInfo.infos[1][0].size()),
73:              HCCL_E_PARA);
74: tempAlgHierachyInfo.push_back(algHierarchyInfo.infos[0][1]);
75: tempAlgHierachyInfo.push_back(algHierarchyInfo.infos[1][0]);

问题描述

  • 访问 infos[1] 前未检查 infos.size() >= 2

修复建议

if (algHierarchyInfo.infos.size() < 2) {
    HCCL_ERROR("algHierarchyInfo.infos size < 2");
    return HCCL_E_PARA;
}
CHK_PRT_RET(algHierarchyInfo.infos[0][1].size() >= algHierarchyInfo.infos[1][0].size(),
             HCCL_ERROR("size mismatch"), HCCL_E_PARA);

问题3:访问 channels[0] 未检查

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:107-111

问题代码

107: remoteRankToChannelInfo_.resize(CONST_ONE);
108: for (auto &channel : resCtx.channels[0]) {
109:     u32 remoteRank = channel.remoteRank;
110:     remoteRankToChannelInfo_[0][remoteRank].push_back(channel);
111: }

问题描述

  • 访问 resCtx.channels[0] 前未检查 channels.size()

修复建议

if (resCtx.channels.size() == 0) {
    HCCL_ERROR("channels size is zero");
    return HCCL_E_PARA;
}
remoteRankToChannelInfo_.resize(CONST_ONE);
for (auto &channel : resCtx.channels[0]) {
    ...
}

问题4:访问 threads[1] 未检查

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_concurrent_executor.cc
行号:136, 310-311

问题代码

136: std::vector<ThreadHandle> subThreads = {resCtx.threads[1]};
...
310: templateAlgResMesh.threads.push_back(resCtx.threads[1]);

问题描述

  • 访问 threads[1] 前未检查 threads.size() >= 2

修复建议

if (resCtx.threads.size() < 2) {
    HCCL_ERROR("threads size < 2");
    return HCCL_E_PARA;
}
std::vector<ThreadHandle> subThreads = {resCtx.threads[1]};

5. 外部输入合法性校验

检视结果FAIL | 置信度:HIGH (90%)

问题1:topoInfo 指针未判空

文件src/ops/all_to_all_v/selector/alltoallv_auto_selector.cc
行号:26-29

问题代码

26: HCCL_DEBUG("[AlltoAllVAutoSelector][%s] start, topoInfo levelNum[%u]", 
               __func__, topoInfo->topoLevelNums);
27: (void)opParam;
28: (void)configAlgMap;
29: if (topoInfo->topoLevelNums > 1) {

问题描述

  • 直接访问 topoInfo 指针成员
  • 未判空,可能导致空指针解引用

修复建议

if (topoInfo == nullptr) {
    HCCL_ERROR("[AlltoAllVAutoSelector] topoInfo is nullptr");
    return SelectorStatus::NOT_MATCH;
}
HCCL_DEBUG("[AlltoAllVAutoSelector][%s] start, topoInfo levelNum[%u]", 
           __func__, topoInfo->topoLevelNums);

问题2:外部数据强转使用

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:159-171

问题代码

159: for (u32 j = 0; j < rankSize_; j++) {
160:     // Send info
161:     u64 curSendCounts = *(static_cast<const u64 *>(param.all2AllVDataDes.sendCounts) + j);
162:     u64 curSendDispls = *(static_cast<const u64 *>(param.all2AllVDataDes.sdispls) + j);

问题描述

  • 外部指针 sendCountssdispls 未判空
  • 直接访问可能导致空指针解引用

修复建议

if (param.all2AllVDataDes.sendCounts == nullptr || param.all2AllVDataDes.sdispls == nullptr) {
    HCCL_ERROR("sendCounts or sdispls is nullptr");
    return HCCL_E_PARA;
}
for (u32 j = 0; j < rankSize_; j++) {
    u64 curSendCounts = *(static_cast<const u64 *>(param.all2AllVDataDes.sendCounts) + j);
    u64 curSendDispls = *(static_cast<const u64 *>(param.all2AllVDataDes.sdispls) + j);
}

问题3:param.varData 指针未判空

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_sole_executor.cc
行号:133-136

问题代码

133: const u64* data = reinterpret_cast<const u64*>(param.varData);
134: // 从varData把值取出来
135: for (u64 i = 0; i < ALL_TO_ALL_V_VECTOR_NUM * rankSize_; i++) {
136:     HCCL_INFO("OrchestrateLoop, param.varData[%u] is [%u]", i, data[i]);

问题描述

  • param.varData 未判空
  • 直接访问可能导致空指针解引用

修复建议

if (param.varData == nullptr) {
    HCCL_ERROR("param.varData is nullptr");
    return HCCL_E_PARA;
}
const u64* data = reinterpret_cast<const u64*>(param.varData);

问题4:buffInfo 指针检查不一致

文件src/ops/all_to_all_v/template/ccu/ccu_temp_all_to_all_v_mesh2die.cc
行号:121-124

问题代码

121: CHK_PRT_RET(buffInfo.inputPtr == nullptr || buffInfo.outputPtr == nullptr,
122:     HCCL_ERROR("..."), buffInfo.inputPtr, buffInfo.outputPtr),
123:     HcclResult::HCCL_E_PTR);

问题描述

  • 该文件检查了 inputPtr 和 outputPtr
  • 但其他模板文件中缺少类似检查
  • 检查逻辑不一致

修复建议
统一所有模板文件中的指针检查逻辑,在入口处统一检查:

if (buffInfo.inputPtr == nullptr || buffInfo.outputPtr == nullptr) {
    HCCL_ERROR("buffer pointer is nullptr");
    return HCCL_E_PTR;
}

7. 访问临界资源需要保护

检视结果FAIL | 置信度:HIGH (85%)

问题1:线程同步返回值未检查完整

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_concurrent_executor.cc
行号:339, 351

问题代码

339: CHK_RET(PreSyncInterThreads(mainThread, subThreads, notifyIdxMainToSub));
...
351: CHK_RET(PostSyncInterThreads(mainThread, subThreads, notifyIdxSubToMain));

问题描述

  • 使用了 CHK_RET 检查返回值
  • 但未检查同步失败后的恢复逻辑
  • 同步失败可能导致死锁

修复建议

HcclResult ret = PreSyncInterThreads(mainThread, subThreads, notifyIdxMainToSub);
if (ret != HCCL_SUCCESS) {
    HCCL_ERROR("PreSyncInterThreads failed, ret=%d", ret);
    // 添加恢复逻辑或清理资源
    return ret;
}

问题2:共享资源访问未完全保护

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_concurrent_executor.cc
行号:341-349

问题代码

341: ret = algTemplateClos->KernelRun(param, tempAlgParamsClos, templateAlgResClos);
342: CHK_PRT_RET(ret != HCCL_SUCCESS, ...);
343: 
344: ret = algTemplateMesh->KernelRun(param, tempAlgParamsMesh, templateAlgResMesh);
345: CHK_PRT_RET(ret != HCCL_SUCCESS, ...);

问题描述

  • 两个 template 并发执行
  • 访问共享资源 param.inputPtr/outputPtr
  • 未完全保护,可能存在资源竞争

修复建议
确认 inputPtr/outputPtr 的并发访问是否需要锁保护:

// 如果需要保护,添加锁机制
std::lock_guard<std::mutex> lock(bufferMutex);
ret = algTemplateClos->KernelRun(param, tempAlgParamsClos, templateAlgResClos);

问题3:线程数组构建未检查

文件src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_concurrent_executor.cc
行号:334-337

问题代码

334: ThreadHandle mainThread = resCtx.threads[0];
335: std::vector<ThreadHandle> subThreads = {resCtx.threads[1]};
336: std::vector<u32> notifyIdxMainToSub = {0};
337: std::vector<u32> notifyIdxSubToMain = {0};

问题描述

  • 直接访问 threads[0]threads[1]
  • 未检查线程资源是否有效

修复建议

if (resCtx.threads.size() < 2) {
    HCCL_ERROR("threads size < 2");
    return HCCL_E_PARA;
}
// 检查线程句柄是否有效
if (!IsValidThread(resCtx.threads[0]) || !IsValidThread(resCtx.threads[1])) {
    HCCL_ERROR("thread handle invalid");
    return HCCL_E_PARA;
}
ThreadHandle mainThread = resCtx.threads[0];
std::vector<ThreadHandle> subThreads = {resCtx.threads[1]};

8. 问题严重性分类

HIGH 严重级别(14个,需立即修复)

位置 类型
alltoall_auto_selector.cc:67 乘法溢出
ins_v2_all_to_all_v_sole_executor.cc:161 偏移溢出
ins_v2_all_to_all_v_sole_executor.cc:305 乘法溢出
ins_v2_all_to_all_v_sole_executor.cc:282 除零风险
ins_v2_all_to_all_v_concurrent_executor.cc:143 除零风险
ins_v2_all_to_all_v_sole_executor.cc:301 除零风险
ins_v2_all_to_all_v_sole_executor.cc:69 数组越界
ins_v2_all_to_all_v_sole_executor.cc:71 数组越界
ins_v2_all_to_all_v_sole_executor.cc:107 数组越界
ins_v2_all_to_all_v_concurrent_executor.cc:136 数组越界
alltoallv_auto_selector.cc:26 指针未判空
ins_v2_all_to_all_v_sole_executor.cc:161 指针未判空
ins_v2_all_to_all_v_sole_executor.cc:133 指针未判空
ins_v2_all_to_all_v_concurrent_executor.cc:339 同步检查

MEDIUM 严重级别(3个,建议修复)

位置 类型
ins_v2_all_to_all_v_concurrent_executor.cc:341 共享资源
ins_v2_all_to_all_v_concurrent_executor.cc:334 线程检查
ccu_temp_all_to_all_v_mesh2die.cc:121 检查不一致

9. 修复优先级建议

第一优先级(立即修复)

  1. 除零保护

    • 位置:ins_v2_all_to_all_v_sole_executor.cc:282-284
    • 影响:程序崩溃
    • 修复:添加除数零值检查
  2. 数组边界检查

    • 位置:ins_v2_all_to_all_v_sole_executor.cc:69-78
    • 影响:内存访问错误
    • 修复:添加数组大小校验
  3. 指针判空

    • 位置:alltoallv_auto_selector.cc:26
    • 影响:空指针解引用
    • 修复:添加指针判空检查
  4. 乘法溢出保护

    • 位置:alltoall_auto_selector.cc:67-68
    • 影响:数据量计算错误
    • 修复:添加溢出检查

第二优先级(建议修复)

  1. 线程同步完整性

    • 位置:ins_v2_all_to_all_v_concurrent_executor.cc:339
    • 影响:可能导致死锁
    • 修复:添加同步失败恢复逻辑
  2. 共享资源保护

    • 位置:ins_v2_all_to_all_v_concurrent_executor.cc:341
    • 影响:资源竞争
    • 修复:评估是否需要锁保护

总结

主要问题

  • 数值运算缺乏保护(除零、溢出)
  • 数组边界检查不完整
  • 外部指针未判空
  • 并发同步机制需完善

建议

  1. 在关键函数入口统一添加参数合法性校验
  2. 所有除法运算前检查除数是否为0
  3. 数组访问前检查边界
  4. 外部指针统一判空
  5. 完善线程同步错误恢复机制
likedislike
LLeewis成员
5月15日 关联了看板:HCCL
Leewis成员
5月15日 评论:

/assign @gcw_dFpssWuk

likedislike
CANN-robotCANN-robot成员
5月15日 将 gcw_dFpssWuk 设为负责人
LLeewis成员
5月15日 修改标题为 “[Bug-Report|缺陷反馈]: alltoallv通信缺陷”,原标题为“alltoallv通信缺陷”
LLeewis成员
5月21日 将 zhuyiming3 设为负责人
LLeewis成员
5月21日 移除了负责人 gcw_dFpssWuk
zhuyiming3成员
5月22日 评论:

问题2.2 在hccl/src/ops/all_to_all_v/all_to_all_v_op.cc的CalcInputOutputSize函数保证偏移不会溢出

likedislike
zhuyiming3成员
5月22日 评论:

问题2.3 maxDataCountPerLoop由u64数据类型的maxDataSizePerLoop除以dataTypeSize_得到,所以相乘后不会溢出

likedislike
zhuyiming3成员
5月22日 评论:

问题3.1 dataTypeSize_由查表得到,表中数据确认无0,rankSize_由算子入口校验,hccl/src/ops/all_to_all_v/all_to_all_v_op.cc中HcomCheckUserRank函数可确保其不为0

likedislike
zhuyiming3成员
5月22日 评论:

问题3.2 factor由u32类型相加,已确保最小值为4

likedislike
zhuyiming3成员
5月22日 评论:

问题3.3 已确认290行有检查是否为0

likedislike
zhuyiming3成员
5月22日 评论:

问题4.1 已确认62行检查algHierarchyInfo.infos[0].size()为2

likedislike
zhuyiming3成员
5月22日 评论:

问题4.2 同问题4.1

likedislike
zhuyiming3成员
5月22日 评论:

问题4.3 已确认103行检查resCtx.channels.size()为1

likedislike
zhuyiming3成员
5月22日 评论:

问题4.4 hccl/src/ops/op_common/op_common.cc:591行thread[0]已赋值,又在1033行push_back threadNum个thread,threadNum可由hccl/src/ops/all_to_all_v/executor/ins_v2_all_to_all_v_concurrent_executor.cc:208行确保最小为1,所以threads.size()大于等于2

likedislike
zhuyiming3成员
5月22日 评论:

问题5.2 已确认在hccl/src/ops/all_to_all_v/all_to_all_v_op.cc的CheckAlltoAllVInputPara中进行空指针校验

likedislike
zhuyiming3成员
5月22日 评论:

问题5.4 已确认inputPtr和outputPtr均来自sendBuf和recvBuf,在算子入口处已检查

likedislike
zhuyiming3成员
5月22日 评论:

问题7.1 同步失败后报错算子调用侧会进行资源回收

likedislike
zhuyiming3成员
5月22日 评论:

问题7.3 算法编排中会进行偏移计算,确保不对共享资源进行冲突访问

likedislike
zhuyiming3成员
5月22日 评论:

问题7.3 此处线程非系统资源线程概念,由业务侧保证有效性

likedislike
Zzhuyiming3成员
5月22日 关联了pull request:fix security warning
Leewis成员
5月25日 评论:

@issuebot 当前issue中确认存在风险的pr已上库,当前issue暂时先关闭了,感谢反馈。

likedislike
LLeewis成员
5月25日 issue状态由 待办的 改变为 已完成
LLeewis成员
5月25日 关闭了 issue
CANN-robotCANN-robot成员
5月25日 添加了label:Accepted
CANN-robotCANN-robot成员
5月25日 添加了label:resolved
LLeewis成员
15 天前 移除了看板:HCCL