Closed
[Bug] circular_pad 单侧 padding=0 时跳过 left/right>inputW 校验(aclnnCircularPad2d) #2484
Agent-Bug-HunterAdd on Aug 3Closed at Aug 10
陈思
Aug 4 Comments:
Aug 4 Comments:
收到,问题确认、修复中


Aug 4 Associated pull request
Aug 4 Deleted associated pull request: fix(conversion): validate pad and slice axes bounds
Aug 4 Assign chensi79 as responsible person
Aug 5 Assign sunchun as responsible person
Aug 5 Removed responsible person chensi79
WangJinCheng
Aug 7 Comments:
Aug 7 Comments:
/assign @Anthony0331


Aug 7 Assign Anthony0331 as responsible person, remove original responsible person: sunchun
Aug 7 Assign Anthony0331 as responsible person, remove original responsible person: sunchun
Aug 9 Associated pull request
Aug 10 Close issue
Aug 10 Added label: resolved
摘要
aclnnCircularPad2d/CircularPadtiling 的CheckLeftAndRight在 一侧 padding 为 0 时跳过“left/right 不得大于 inputW”的校验:环境
2d1098d3e902cann-ops-math-cann_scan_repro_linux-*.run→$ASCEND_HOME_PATH/vendors/cann_scan_repro_math为什么认为这是问题:期望 vs 实际
输入(与复现用例一致)
期望行为
实际行为(aclnn / 源码编译安装路径)
对比结论
根因
文件:
OPS_MATH/conversion/circular_pad/op_host/circular_pad_tiling.cppif (left > 0 && right > 0 && (left > inputW || right > inputW)) { ... fail; }见同目录 FINDING.md / 复现用例注释。
为何确认跑的是源码编译内核(非 built-in)
source $ASCEND_HOME_PATH/vendors/cann_scan_repro_math/bin/set_env.bash,ASCEND_CUSTOM_OPP_PATH指向该 vendor。op_api/op_impl,而非仅依赖 CANN built-in 同名算子(见repro_manifest.json中built_from_source=true)。完整复现过程
占位符:
$ASCEND_HOME_PATH/$OPS_MATH/$REPRO_ROOT。步骤 1:环境使能
source <CANN安装目录>/ascend-toolkit/set_env.sh步骤 2:源码编译单算子包
cd "$OPS_MATH" bash build.sh --pkg --soc=ascend910b --ops=circular_pad \ --vendor_name=cann_scan_repro -j8成功标志:生成
$OPS_MATH/build_out/cann-ops-math-cann_scan_repro_linux-*.run步骤 3:安装并切换到自定义包
bash $OPS_MATH/build_out/cann-ops-math-cann_scan_repro_linux-*.run \ --quiet --install-path="$ASCEND_HOME_PATH" source "$ASCEND_HOME_PATH/vendors/cann_scan_repro_math/bin/set_env.bash" echo "ASCEND_CUSTOM_OPP_PATH=$ASCEND_CUSTOM_OPP_PATH"步骤 4:放置复现源码与执行脚本
(本 draft 目录内已含上述文件,可直接作为
$REPRO_ROOT。)步骤 5:编译并运行
cd "$REPRO_ROOT" chmod +x build_and_run_repro.sh bash build_and_run_repro.sh --vendor cann_scan_repro --src test_aclnn_circular_pad_oneside.cpp # 退出码 42 = BUG_REPRODUCED成功复现标志:进程退出码 42。
实际运行摘录
复现用例源码
文件名:
test_aclnn_circular_pad_oneside.cpp/** * MATH-CIRCPAD-001 Track A — conversion/circular_pad * CheckLeftAndRight skips when one side==0: left>inputW && right==0 reaches kernel. * Exit 42 = accepted illegal pad (bug); 0 = rejected; 1 = harness error. */ #include <cstdio> #include <cstdint> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_circular_pad2d.h" #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) static int64_t GetShapeSize(const std::vector<int64_t>& shape) { int64_t n = 1; for (auto i : shape) { n *= i; } return n; } static int Init(int32_t deviceId, aclrtStream* stream) { auto ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); ret = aclrtSetDevice(deviceId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); ret = aclrtCreateStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); return 0; } template <typename T> static int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size = GetShapeSize(shape) * sizeof(T); auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); std::vector<int64_t> strides(shape.size(), 1); for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; i--) { strides[i] = shape[i + 1] * strides[i + 1]; } *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); CHECK_RET(ret == 0, return 1); // inputW=2; padding = {left,right,top,bottom} = {3,0,0,0}: left>inputW, right==0 // CheckLeftAndRight first branch requires left>0 && right>0 — skipped → reaches kernel. std::vector<int64_t> selfShape = {1, 1, 2, 2}; std::vector<int64_t> outShape = {1, 1, 2, 5}; // W: 2+3+0=5 void *selfDev = nullptr, *outDev = nullptr; aclTensor *self = nullptr, *out = nullptr; aclIntArray* padding = nullptr; std::vector<float> selfHost = {1, 2, 3, 4}; std::vector<int64_t> paddingData = {3, 0, 0, 0}; std::vector<float> outHost(10, -999.f); ret = CreateAclTensor(selfHost, selfShape, &selfDev, ACL_FLOAT, &self); CHECK_RET(ret == 0, return 1); ret = CreateAclTensor(outHost, outShape, &outDev, ACL_FLOAT, &out); CHECK_RET(ret == 0, return 1); padding = aclCreateIntArray(paddingData.data(), 4); CHECK_RET(padding != nullptr, return 1); uint64_t workspaceSize = 0; aclOpExecutor* executor = nullptr; ret = aclnnCircularPad2dGetWorkspaceSize(self, padding, out, &workspaceSize, &executor); LOG_PRINT("GetWorkspaceSize ret=%d %s\n", ret, ret == 0 ? "(SUCCESS — illegal left>W,right=0 not rejected)" : "(rejected/err)"); bool accepted = (ret == 0); int syncRet = -1; if (accepted) { void* workspaceAddr = nullptr; if (workspaceSize > 0) { aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); } ret = aclnnCircularPad2d(workspaceAddr, workspaceSize, executor, stream); LOG_PRINT("aclnnCircularPad2d ret=%d\n", ret); syncRet = aclrtSynchronizeStream(stream); LOG_PRINT("SynchronizeStream ret=%d\n", syncRet); if (syncRet == 0) { std::vector<float> result(10, -999.f); aclrtMemcpy(result.data(), result.size() * sizeof(float), outDev, 10 * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); LOG_PRINT("out:"); for (float v : result) { LOG_PRINT(" %.3f", v); } LOG_PRINT("\n"); } if (workspaceAddr) { aclrtFree(workspaceAddr); } } aclDestroyTensor(self); aclDestroyTensor(out); aclDestroyIntArray(padding); aclrtFree(selfDev); aclrtFree(outDev); aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); if (accepted && syncRet == 0) { LOG_PRINT("BUG_REPRODUCED: left>inputW && right==0 accepted\n"); return 42; } LOG_PRINT("NO_REPRO\n"); return 0; }执行脚本
文件名:
build_and_run_repro.sh#!/usr/bin/env bash # Builtin aclnn headers/libs + ASCEND_CUSTOM_OPP_PATH for source-built kernels. set -euo pipefail VENDOR="" SRC_NAME="" while [[ $# -gt 0 ]]; do case "$1" in --vendor) VENDOR="$2"; shift 2 ;; --src) SRC_NAME="$2"; shift 2 ;; *) echo "unknown arg: $1" >&2; exit 2 ;; esac done : "${ASCEND_HOME_PATH:?}" ROOT="$(cd "$(dirname "$0")" && pwd)" if [[ -z "$SRC_NAME" ]]; then mapfile -t _srcs < <(ls "$ROOT"/test_aclnn_*.cpp 2>/dev/null || true) [[ ${#_srcs[@]} -eq 1 ]] || { echo "need --src"; exit 2; } SRC="${_srcs[0]}" else SRC="$ROOT/$SRC_NAME" fi BIN="${SRC%.cpp}" if [[ -n "$VENDOR" ]]; then for cand in \ "${ASCEND_HOME_PATH}/vendors/${VENDOR}_math" \ "${ASCEND_HOME_PATH}/vendors/${VENDOR}" do if [[ -f "$cand/bin/set_env.bash" ]]; then set +u; source "$cand/bin/set_env.bash"; set -u echo "[env] sourced $cand/bin/set_env.bash" echo "[env] ASCEND_CUSTOM_OPP_PATH=${ASCEND_CUSTOM_OPP_PATH:-}" break fi done fi INC="${ASCEND_HOME_PATH}/aarch64-linux/include" LIB="${ASCEND_HOME_PATH}/aarch64-linux/lib64" echo "[build] g++ $SRC (builtin opapi + custom opp)" g++ -std=c++17 -O2 "$SRC" \ -I"$INC" -I"$INC/aclnnop" \ -L"$LIB" -Wl,-rpath,"$LIB" \ -lascendcl -lnnopbase -lopapi \ -o "$BIN" echo "[run] $BIN" set +e; "$BIN"; RC=$?; set -e echo "[exit] $RC (42=BUG_REPRODUCED, 0=NO_REPRO, 1=harness error)" exit "$RC"修复建议
在 host/tiling/kernel 入口拒绝非法索引或控制量,返回明确参数错误;勿静默 OOB。
人工复核说明
Agent 复现结果供参考;语义边界(是否允许 wrap、文档是否声明调用方契约)以人工结论与产品规范为准。