CANN Runtime RTS 错误码 EE1020(Invalid Argument)深度解析与排查指南
2026/9/19 16:34:20 网站建设 项目流程

CANN Runtime RTS 错误码 EE1020(Invalid Argument)深度解析与排查指南

【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime

EE1020 是 CANN Runtime 的 RTS(Runtime Service)错误码之一,专门用于报告 Runtime 内部调用标准库安全函数(如memcpy_smemset_s)失败时产生的参数/执行异常。本文以 docs/en/error_code_ref/RTS-Errors/EE1020-Invalid_Argument.md 为主线,结合仓库源码中的错误码元数据、日志输出链路、各 API 触发点与单元测试,完整拆解 EE1020 的消息格式、触发场景与排查方法,帮助你遇到该错误时能快速定位到具体的函数调用与参数问题。

一、错误码概览

  • 错误码:EE1020
  • 错误类型:Invalid Argument(参数无效)
  • 错误分类:RTS Errors(Runtime 服务错误)
  • 错误级别:Error(日志级别DLOG_ERROR,见 error_code_meta.h)
  • 适用模块:CANN Runtime 的 Host 侧 API 层与核心任务构建层
  • 本质:Runtime 内部调用 C 标准库安全函数(memcpy_smemset_s等)时,函数返回值不等于EOK(成功),说明发生了缓冲区参数不合法或内存操作失败。这类失败通常意味着传入 API 的缓冲区地址、长度或指针参数存在问题。

EE1020 与常见的参数校验错误码(如 EE1003、EE1004)不同:EE1003/EE1004 是 Runtime 对用户传入 API 的参数直接做合法性检查时抛出的;而 EE1020 是参数已通过外层校验、但在进入标准安全函数后被底层拒绝时抛出的,因此其定位线索藏在消息的“标准函数名 + errno + 扩展信息”三要素中。

二、错误消息格式与占位符语义

EE1020 的标准报错格式如下:

%s failed. Reason: Standard function %s failed. [Errno %s] %s. %s

依次出现的占位符%s含义如下:

占位符参数名含义
第 1 个%sfunc1失败的 Runtime 接口名称(外层 API,如rtGetSocVersion
第 2 个%sfunc2失败的标准函数名称(内层,如memcpy_s
第 3 个%sret_code标准函数返回的错误码(errno 数值)
第 4 个%sreason错误原因(通常由strerror输出的错误码文本描述)
第 5 个%sextend_info扩展信息(打印涉及的内存地址、缓冲区长度等关键现场数据)

需要说明的是,该格式在源码元数据中注册的完整模板为:

%s failed. Reason: Standard function %s failed. [Errno %s] %s. %s ErrorCode=EE1020.

即实际打印的日志末尾会追加ErrorCode=EE1020.字样,便于在日志中直接检索定位(参见 error_code_meta.h 与 error_code.json 中的ErrMessage字段)。

三、典型报错示例逐字段解读

原文档给出了一个典型报错:

rtGetStreamId failed. Reason: Standard function memcpy_s failed. [Errno 1] Operation not permitted. src=socName, dest=3257281401236631602, dest_max=1223, count=1222.

逐字段拆解:

片段对应参数解读
rtGetStreamId failedfunc1外层失败接口为rtGetStreamId(获取 Stream ID)
Standard function memcpy_s failedfunc2内层失败函数为内存拷贝安全函数memcpy_s
[Errno 1]ret_codememcpy_s返回错误码 1
Operation not permittedreason错误码 1 对应的文本描述(errno 1 =EPERM
src=socName, dest=...extend_info扩展现场信息:源、目标地址、目标缓冲区最大长度dest_max、拷贝字节数count

结合源码可以还原这一报错的完整现场:

  • rtGetStreamId是获取 Stream 唯一 ID 的接口,位于 api_c.cc;
  • 接口内部通过memcpy_s(dest, destMax, src, count)将字符串(如 SOC 版本名socName)拷入用户缓冲区;
  • memcpy_s返回值不为EOK时,代码构造std::stringstream扩展信息,记录destsrcdestMaxcount等十六进制/十进制现场值,并通过日志宏打印 EE1020 消息后返回失败错误码。

扩展信息中的字段是定位的核心:

  • dest/dest=0x...:目标缓冲区地址;
  • src/src=0x...:源数据地址;
  • dest_max/destMax/maxLen:目标缓冲区最大容量;
  • count/length/paraSize:实际拷贝字节数。

count > dest_max或目标缓冲区为无效地址时,memcpy_s将返回非零错误码并触发 EE1020。上例中dest_max=1223, count=1222恰好说明目标缓冲区容量仅比拷贝长度大 1 字节——这正是典型的目标缓冲区空间不足(或长度边界计算错误)导致memcpy_s失败的情形。

四、源码级实现原理:EE1020 从定义到打印的完整链路

4.1 错误码元数据定义

EE1020 在 error_code_meta.h 中通过 X-Macro 表注册,一行即可完成参数名列表、消息模板与日志级别的声明:

X(EE1020, "EE1020", ("func1", "func2", "ret_code", "reason", "extend_info"), "%s failed. Reason: Standard function %s failed. " "[Errno %s] %s. %s ErrorCode=EE1020.\n", DLOG_ERROR)
  • 参数名列表("func1", "func2", "ret_code", "reason", "extend_info")与文档中的占位符一一对应;
  • 消息模板带\n结尾,保证每条错误日志独立成行;
  • 日志级别为DLOG_ERROR,属于错误级日志。

同一表中还并列定义了 EE1001~EE1024、EE2002、EE4002、EZ2001、WE0001 等错误码,EE1020 专门预留给了“标准函数调用失败”这一场景。此外,error_code.json 中同步维护了对外发布版本的错误码描述(errTitleInvalid_ArgumentArglistfunc1, func2, ret_code, reason, extend_info),供错误码查询工具与文档生成使用。

4.2 枚举与打印函数

EE1020 同时被注册进ErrorCode枚举(rt_log.h),并配套两个核心函数:

std::vector<std::string> GetParamNames(ErrorCode code); void PrintErrMsgToLog(ErrorCode errCode, const char* file, const int32_t line, const char* func, const std::vector<std::string>& values);
  • GetParamNames根据错误码返回参数名列表,用于格式化时的参数校验(参数数量必须与Arglist一致);
  • PrintErrMsgToLogvalues按模板顺序填充后打印到日志;
  • ProcessErrorCodeImpl负责错误码处理与错误码的最终落盘。

各 API 中实际使用的是封装宏RT_LOG_OUTER_MSG_IMPL(ErrorCode::EE1020, func1, func2, retCode, reason, extendInfo),它把调用点函数名、标准函数名、错误码数值、strerror文本与扩展信息统一组装后走PrintErrMsgToLog输出,并通过GetRtExtErrCodeAndSetGlobalErr将错误映射为对外返回码(如RT_ERROR_SEC_HANDLERT_ERROR_INVALID_VALUE)。

五、EE1020 的主要触发场景(源码实测)

通过检索源码中所有ErrorCode::EE1020的使用点,可以归纳出以下触发场景:

5.1 查询类接口中的字符串拷贝失败

api_c_soc.cc 的rtGetSocVersion:将 SOC 版本名(或UNKNOWN_SOC_TYPE)通过memcpy_s拷入用户缓冲区ver。当用户传入的maxLen不足以容纳版本字符串 + 终止符(socName.length() + 1U)时,memcpy_s失败并打印 EE1020,返回RT_ERROR_INSTANCE_VERSIONRT_ERROR_SEC_HANDLE。文档示例中rtGetStreamId场景与此同属“字符串/结构体拷入用户缓冲区”类。

5.2 Kernel 启动参数配置类接口

  • api_c.cc 的rtConfigureCall:当smDesc非空时,将调度描述符拷入线程局部的LaunchArgment,失败即报 EE1020;
  • api_c_kernel.cc 的rtsKernelArgsParaUpdate:把内核参数para拷入参数句柄缓冲区(memcpy_s(offset, paraSize, para, paraSize)),失败时扩展信息打印dest=0x..., para=0x..., maxLen=..., paraSize=...
  • api_impl_kernel_args.cc:向内核参数句柄追加占位符参数时,memcpy_s失败会以"Adding placeholder parameters to the kernel parameter handle"作为func1报 EE1020;
  • api_impl.cc:rtSetupArgument设置内核启动参数时,对偏移与大小校验后执行memcpy_s,失败报 EE1020。

5.3 Profiling 与维测接口

  • api_c.cc 的rtsProfTrace:将rtProfTraceUserData从用户内存拷入栈上局部变量(memcpy_s(&data, sizeof(data), userdata, length)),若传入的length超过结构体大小或为非法地址即触发;
  • api_impl_david.cc:获取内存 UCE(Uncorrectable Error)信息时,memcpy_s失败以"Getting memory uce info"func1报 EE1020。

5.4 核心任务构建层

除 API 层外,任务/命令构建路径中也有 EE1020 的使用点,例如 cmo_task.cc、memory_memcpy_async_task.cc、task_to_sqe.cc、arg_manage_ub.cc。从这些文件的使用位置可以推断:在向任务队列(SQE)或 UB 参数区填充数据时,若缓冲区长度校验失败,同样通过 EE1020 上报——这印证了该错误码“贯穿 Runtime 所有内存拷贝关键路径”的定位。

5.5 单元测试验证

tests/ut/runtime/runtime/test/rt_error_code_test.cc 对 EE1020 做了系统验证:

  • 使用 5 个参数调用PrintErrMsgToLog(ErrorCode::EE1020, ...),验证参数数量与格式模板匹配;
  • 构造rtGetSocVersion场景:ErrorCode::EE1020, "rtGetSocVersion", "memcpy_s", "1", "count is greater than dest_max",验证memcpy_s返回错误码 1(count超过dest_max)时消息拼接正确;
  • 通过GetParamNames(ErrorCode::EE1020)校验参数名列表为 5 项;
  • 校验参数数量表:{ErrorCode::EE1020, 5},确保错误码与期望参数个数绑定,参数个数不匹配时会触发断言。

这说明 EE1020 的消息格式、参数数量与打印行为均有自动化测试兜底,任何一处改动都会在 UT 阶段暴露。

六、排查与解决方法

EE1020 的官方解决建议是“按照报错提示定位问题”。结合源码,建议按以下步骤排查:

  1. 记录完整报错:务必保留日志中[Errno N]、错误原因文本与扩展信息(srcdestdest_maxcount)三个部分,缺一不可;
  2. 核对 errno 与原因文本
    • [Errno 1] Operation not permitted:安全函数返回EPERM,多为内存区域访问权限或缓冲区归属异常;
    • [Errno 22] Invalid argument等:检查传入的目标缓冲区是否为合法地址、dest_max是否为真实可用容量;
    • 若原因文本提示count is greater than dest_max,说明拷贝长度超过目标缓冲区容量,优先检查长度参数计算是否包含字符串终止符\0(源码中字符串场景统一为length + 1U)。
  3. 对照func1定位接口func1是外层 API 名,结合上文的触发场景表,可迅速判断是查询类(rtGetSocVersion)、内核参数类(rtConfigureCallrtsKernelArgsParaUpdate)还是 Profiling 类(rtsProfTrace)接口;
  4. 检查调用方缓冲区管理:多数 EE1020 源于调用方提供的缓冲区过小或指针失效。对照dest_maxcount,调整缓冲区分配策略或修正长度参数后重试;
  5. 检索官方文档:可参考本仓库 RTS-Errors.md 错误码目录及中文版 EE1020-Invalid_Argument.md 交叉核对;
  6. 保留现场日志:若问题无法通过参数修正解决,保留带ErrorCode=EE1020的完整日志(含时间戳、上下文与扩展信息)提交给 Runtime 团队分析——扩展信息中的十六进制地址与长度是定位内存问题的关键证据。

七、与其他 RTS 参数类错误码的区分

EE1020 属于“参数无效”大类,但触发时机特殊。使用时应与同类错误码区分:

错误码触发时机典型场景
EE1003参数取值不合法,消息中带“期望值”值域越界(如长度不在[0, 255]
EE1004参数为空指针指针类参数为 NULL
EE1017参数不合法,带原因描述参数关系不满足(如paraSize不相等)
EE1020外层校验通过后,标准安全函数(memcpy_s等)执行失败缓冲区容量不足、内存拷贝失败
EE1022多个参数取值不合法多参数同时越界

一句话记忆:EE1003/EE1004 是“还没开始拷就发现参数不对”,EE1020 是“参数看起来没问题、但拷的时候被安全函数拒绝”。因此 EE1020 的报错信息里永远会带标准函数名与 errno,这是它最鲜明的特征。

八、总结

EE1020 是 CANN Runtime 报告“内部标准安全函数调用失败”的统一错误码,其消息中完整保留了外层 API、内层标准函数、errno、原因文本与内存现场五要素,排查价值极高。通过 error_code_meta.h 的元数据定义、rt_log.h 的打印链路、api_c_soc.cc 等触发点以及 rt_error_code_test.cc 的测试覆盖,开发者可以快速建立“报错 → 函数 → 缓冲区 → 长度”的定位路径。遇到该错误时,优先核对dest_maxcount的关系以及缓冲区归属,绝大多数场景均可通过修正缓冲区容量或长度参数解决。

【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询