已关闭
[Bug-Report|缺陷反馈]: aclnnFmodScalar/aclnnInplaceFmodScalar 的 other 传空指针返回 561103,资料声明 161001 #4176
liuhanwen8创建于  7 天前关闭于  5 天前
liuhanwen8
liuhanwen8
7 天前 创建

一、问题描述 (必填)

aclnnFmodScalarGetWorkspaceSize / aclnnInplaceFmodScalarGetWorkspaceSize 在 other(aclScalar)传空指针时返回 561103(ACLNN_ERR_INNER_NULLPTR,内部错误),而本接口资料错误码表明确声明该场景应返回 161001(ACLNN_ERR_PARAM_NULLPTR,参数错误)。

同一错误码表条目下的 self / out 空指针确实返回 161001,三个形参处理口径不一致。

资料原文(math/mod/docs/aclnnFmodScalar&aclnnInplaceFmodScalar.md)

aclnnFmodScalar 段(L174-178):

返回码 错误码 描述
ACLNN_ERR_PARAM_NULLPTR 161001 传入的self、other或out是空指针。

aclnnInplaceFmodScalar 段(L330-333)同型:

返回码 错误码 描述
ACLNN_ERR_PARAM_NULLPTR 161001 传入的selfRef、other是空指针。

实测结果

场景 构造 资料期望 实测 判定
合法基线 self=fp32[4,2], other=fp32(3.0), out=fp32[4,2] 0 0 一致
self 空指针 self=nullptr 161001 161001 一致
out 空指针 out=nullptr 161001 161001 一致
other 空指针(aclnnFmodScalar) other=nullptr 161001 561103 不一致
other 空指针(aclnnInplaceFmodScalar) other=nullptr 161001 561103 不一致
other 空指针重跑 5 次 同上 161001 561103 × 5 稳定复现

复现率 5/5;阴性对照(合法基线返回 0、self/out 空指针返回 161001)均成立,可排除构造问题。

错误码常量对照(CANN 9.2.0 include/aclnn/opdev/op_errno.h 现抄)

#define ACLNN_ERR_PARAM_NULLPTR 161001
#define ACLNN_ERR_PARAM_INVALID 161002
#define ACLNN_ERR_INNER_NULLPTR 561103

代码定位

math/mod/op_api/aclnn_fmod_scalar.cpp:199-202

    // 将other scalar转换为tensor
    CHECK_RET(other != nullptr, ACLNN_ERR_INNER_NULLPTR);      // ← other 判空用内部错误码
    auto otherTensor = uniqueExecutor.get()->ConvertToTensor(other, other->GetDataType());
    CHECK_RET(otherTensor != nullptr, ACLNN_ERR_INNER_NULLPTR);

而 self / out 的判空走 CheckNotNull() → CheckParams() → ACLNN_ERR_PARAM_NULLPTR(同文件 :49-56、:175-190)。

根因:other(aclScalar)的判空被放在 GetWorkspaceSizeCommon 里、早于 CheckParams,且返回内部错误码;self / out 的判空在 CheckParams 内、返回参数错误码。两处口径分裂。

aclnnInplaceFmodScalarGetWorkspaceSize 与 out-of-place 版共用 GetWorkspaceSizeCommon(:265-270 → :192),因此两个接口同时受影响。

影响

  1. 调用方按资料写 if (ret == ACLNN_ERR_PARAM_NULLPTR) 处理空指针入参时会漏判;
  2. 561103 落在「内部错误」区间(561xxx),上层框架会把它归类为算子内部故障而非调用方参数错误,在框架适配层可能被误报成内核异常、触发重试或熔断;
  3. 该判空早于 CheckParams 执行,导致「self 非法 + other 为空」的组合也被这个内部错误码抢先拦截,进一步放大影响面。

二、环境信息 (可选)

  • 昇腾硬件型号:Ascend 910B3(npu-smi 26.1.1 显示 910B3,8 die)
  • CANN 版本:9.2.0(/usr/local/Ascend/cann-9.2.0)
  • 操作系统:Linux aarch64(openEuler / kernel 同 CANN 9.2.0 配套版本)
  • 其他:g++ 10.3.1;libopapi_math.so 提供 aclnnFmodScalar 符号;该 SoC 走 CANN 内置 ops_legacy 的 Mod 实现,本问题属 aclnn 接口层(host 侧)行为,与 kernel 版本无关
  • 仓库基线:cann/ops-math master d8fc7a6

三、重现步骤 (可选)

自包含 C++ 复现(两段式接口直调,一场景一进程),完整代码如下:

// build:
//   g++ -O2 -std=c++17 repro.cpp -o fmod_repro \
//     -I/usr/local/Ascend/cann-9.2.0/include \
//     -L/usr/local/Ascend/cann-9.2.0/aarch64-linux/lib64 \
//     -lascendcl -lnnopbase -lopapi_math -lopapi
// run:
//   source /usr/local/Ascend/ascend-toolkit/set_env.sh
//   export LD_LIBRARY_PATH=/usr/local/Ascend/cann-9.2.0/aarch64-linux/lib64:$LD_LIBRARY_PATH
//   ./fmod_repro other_null   # -> 561103(异常)
//   ./fmod_repro self_null    # -> 161001(对照)
//   ./fmod_repro out_null     # -> 161001(对照)
//   ./fmod_repro ok           # -> 0     (阴性对照)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <vector>
#include <unistd.h>
#include "acl/acl.h"
#include "aclnnop/aclnn_fmod_scalar.h"

int main(int argc, char** argv)
{
    setvbuf(stdout, nullptr, _IONBF, 0);
    const char* sc = (argc > 1) ? argv[1] : "ok";
    int32_t dev = 0;
    const char* e = getenv("FMOD_DEV");
    if (e != nullptr) dev = atoi(e);
    bool inplace = (getenv("FMOD_OP") != nullptr && strcmp(getenv("FMOD_OP"), "inplace") == 0);

    aclInit(nullptr);
    if (aclrtSetDevice(dev) != ACL_SUCCESS) { printf("SetDevice(%d) failed\n", dev); return 11; }
    aclrtStream stream = nullptr;
    aclrtCreateStream(&stream);

    std::vector<int64_t> sh = {4, 2};
    std::vector<int64_t> sd = {2, 1};
    int64_t n = 8;
    std::vector<float> host((size_t)n, 0.0f);
    for (int64_t i = 0; i < n; i++) host[(size_t)i] = (float)(i * 7 + 3);
    void* dS = nullptr;
    void* dO = nullptr;
    aclrtMalloc(&dS, (size_t)(n * 4), ACL_MEM_MALLOC_HUGE_FIRST);
    aclrtMalloc(&dO, (size_t)(n * 4), ACL_MEM_MALLOC_HUGE_FIRST);
    aclrtMemcpy(dS, (size_t)(n * 4), host.data(), (size_t)(n * 4), ACL_MEMCPY_HOST_TO_DEVICE);

    aclTensor* self = aclCreateTensor(sh.data(), 2, ACL_FLOAT, sd.data(), 0, ACL_FORMAT_ND, sh.data(), 2, dS);
    aclTensor* out  = aclCreateTensor(sh.data(), 2, ACL_FLOAT, sd.data(), 0, ACL_FORMAT_ND, sh.data(), 2, dO);
    float otherVal = 3.0f;
    aclScalar* other = aclCreateScalar(&otherVal, ACL_FLOAT);

    if (strcmp(sc, "self_null") == 0)  self  = nullptr;
    if (strcmp(sc, "other_null") == 0) other = nullptr;
    if (strcmp(sc, "out_null") == 0)   out   = nullptr;

    uint64_t ws = 0;
    aclOpExecutor* exec = nullptr;
    aclnnStatus r1 = inplace
        ? aclnnInplaceFmodScalarGetWorkspaceSize(self, other, &ws, &exec)
        : aclnnFmodScalarGetWorkspaceSize(self, other, out, &ws, &exec);
    printf("scenario=%s op=%s GetWorkspaceSize = %d\n", sc, inplace ? "inplace" : "outofplace", (int)r1);

    int r2 = -999;
    if (r1 == 0) {
        void* w = nullptr;
        if (ws > 0) aclrtMalloc(&w, ws, ACL_MEM_MALLOC_HUGE_FIRST);
        r2 = (int)(inplace ? aclnnInplaceFmodScalar(w, ws, exec, stream)
                           : aclnnFmodScalar(w, ws, exec, stream));
        aclrtSynchronizeStream(stream);
        printf("scenario=%s Execute = %d\n", sc, r2);
        if (w) aclrtFree(w);
    }
    fflush(stdout);
    _exit(0);
}

实测输出(Ascend 910B3 / CANN 9.2.0):

$ ./fmod_repro ok          ->  scenario=ok         GetWorkspaceSize = 0        Execute = 0
$ ./fmod_repro self_null   ->  scenario=self_null  GetWorkspaceSize = 161001
$ ./fmod_repro out_null    ->  scenario=out_null   GetWorkspaceSize = 161001
$ ./fmod_repro other_null  ->  scenario=other_null GetWorkspaceSize = 561103   ← 应为 161001
$ FMOD_OP=inplace ./fmod_repro other_null
                           ->  scenario=other_null op=inplace GetWorkspaceSize = 561103  ← 应为 161001

重复 5 次,other_null 恒为 561103。

四、预期结果 (可选)

other 传空指针时返回 161001(ACLNN_ERR_PARAM_NULLPTR),与资料错误码表及 self/out 的现有行为保持一致。

建议修复(math/mod/op_api/aclnn_fmod_scalar.cpp:200):

-    CHECK_RET(other != nullptr, ACLNN_ERR_INNER_NULLPTR);
+    CHECK_RET(other != nullptr, ACLNN_ERR_PARAM_NULLPTR);

或将 scalar 判空并入 CheckNotNull 并统一使用 ACLNN_ERR_PARAM_NULLPTR。因两个接口共用 GetWorkspaceSizeCommon,一处修改即可同时修复 aclnnFmodScalar 与 aclnnInplaceFmodScalar。

💡 备注(选填)

同类先例(本仓已受理的同类「空指针/非法入参返回 561103 而非 161001/161002」问题),可见这不是孤例,而是同一类错误码口径分裂:

  • #3936 aclnnBitwiseNot self 传空指针返回 561103,资料声明 161001
  • #3931 aclnnDiagFlat 空指针返回 561103,资料声明 161001
  • #3928 aclnnLinspace 出参空指针返回 561103,资料声明 161001
  • #3913 aclnnLtScalar/aclnnInplaceLtScalar 空指针入参返回 561103,资料声明 161001
  • #4011 aclnnBitwiseOrScalar out dtype 不支持返回 561103,资料声明 161002

查重说明:已翻查 cann/ops-math 全部 1200 条 issue,aclnnFmodScalar 相关仅有 #4149(头文件公式用 floor 与资料 trunc 不符),属不同问题(那条是文档公式口径,本单是接口层返回码),不重复。

本次挖掘已核对一致的项(同批排查,非本单内容,供参考排除范围):8 种 dtype(DOUBLE/BFLOAT16/FLOAT16/FLOAT32/INT32/INT64/INT8/UINT8)全部可用且数值正确;rank 0-8 边界(rank9 正确返回 161002);out shape 与 self 不一致(返回 161002);self 为 int16/bool/complex64 等不在支持面(返回 161002);空 tensor(返回 0);NaN/±inf/除零特殊值行为符合 IEEE-754;多线程 4 线程 × 100 次并发调用 0 失败。

likedislike
陈思
陈思成员
6 天前 评论:

您好,感谢反馈!

问题分析

核对 cann/ops-math 固定版本 8c1f633e3679,可以确认返回码与接口资料存在不一致:两个接口均约定 other 为空时返回 ACLNN_ERR_PARAM_NULLPTR(161001)。

在 aclnn_fmod_scalar.cpp 的 GetWorkspaceSizeCommon 中,原始 aclScalar* other 在 ConvertToTensor 前被显式判空,但该分支返回的是 ACLNN_ERR_INNER_NULLPTR(561103)。后续 CheckParams 检查 self、转换后的标量 Tensor 和 out 时,空指针才按 161001 处理。这解释了您报告的 other 与 self/out 返回码差异;该路径在 host 侧参数检查阶段即返回,尚未进入 Mod 计算。

aclnnFmodScalarGetWorkspaceSize 和 aclnnInplaceFmodScalarGetWorkspaceSize 都直接返回这个公共函数的结果,因此两个接口同时受影响。当前完成的是源码核查,报告中的设备运行结果尚未由我们独立复测。

处理方向

一个可行的最小调整是在公共函数中,将原始 other 判空分支的返回码改为 ACLNN_ERR_PARAM_NULLPTR,继续在解引用和转换前拦截空指针。紧随其后的 otherTensor == nullptr 表示非空 scalar 的内部转换结果异常,仍应保留内部错误码,避免混淆调用方参数错误与内部失败。

该调整可同时覆盖普通和原地接口;验证重点是两接口 other=nullptr 的返回码,以及已有 self/out/selfRef 空指针和合法调用的行为。我们会继续跟踪这一返回码差异。

likedislike
陈思陈思成员
6 天前 将 chen_0715 设为负责人
陈思陈思成员
6 天前 添加了label:pending-confirmation
Cchenyifeng成员
6 天前 将 m0_55003149 设为负责人
Cchenyifeng成员
6 天前 移除了负责人 chen_0715
weikeweike成员
5 天前 关联了pull request:[BugFix] 修正FmodScalar空标量错误码并补充AddN回归
CANN-robotCANN-robot成员
5 天前 关闭了 issue
CANN-robotCANN-robot成员
5 天前 添加了label:resolved