CANN Runtime 错误码 EH0008 深度解析:Invalid Argument Null Pointer 空指针参数排查指南

发布时间:2026/9/19 17:11:36
CANN Runtime 错误码 EH0008 深度解析:Invalid Argument Null Pointer 空指针参数排查指南 CANN Runtime 错误码 EH0008 深度解析Invalid Argument Null Pointer 空指针参数排查指南【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime导读本文围绕 CANN Runtime 开源仓库中 EH0008 错误码文档 展开系统讲解 ACLAscendCL接口在传入空指针参数时触发的EH0008 Invalid_Argument_Null_Pointer错误包括错误消息的完整格式与占位符含义、源码中参数校验宏与错误上报的完整调用链、典型触发场景与示例以及基于仓库样例代码的可复现排查方案。读完本文你将能够快速定位任意出现cannot be a NULL pointer报错的 ACL API 调用并掌握从报错文本反查出错参数的方法论。错误码定位EH0008 在 ACL Errors 体系中的位置EH0008 属于 CANN Runtime 错误码参考中ACL Errors大类见 ACL Errors 索引错误类型为Invalid_Argument_Null_Pointer即非法参数——空指针。在仓库的维测错误码注册表 src/dfx/error_manager/error_code.json 中该错误码被正式登记为{ errClass: ACL Errors, errTitle: Invalid_Argument_Null_Pointer, ErrCode: EH0008, ErrMessage: %s failed because %s cannot be a NULL pointer., Arglist: func, param, suggestion: { Possible Cause: N/A, Solution: Try again with a correct pointer argument. } }从注册表可以看到两个关键信息参数列表Arglistfunc, param——即该错误只携带两个动态占位内容分别是出错阶段/API 名称与出错参数名官方建议Solution使用正确的指针参数重试即修复调用侧传入的指针值。说明错误码参考中的英文原文位于docs/en/error_code_ref/ACL-Errors/中文对照索引见 docs/zh/error_code_ref/ACL-Errors/README.md两套目录下的错误码编号与消息模板一致。错误消息格式解析两个 %s 占位符的含义原文档明确给出了 EH0008 的错误消息模板%s failed because %s cannot be a NULL pointer.两个%s占位符按顺序依次表示占位符含义示例取值第 1 个%s出错阶段error stage或 API 名称aclrtSynchronizeStream、aclrtGetVersion第 2 个%s出错的参数名parameter namestream、majorVersion原文档给出的标准报错示例aclrtSynchronizeStream failed because stream cannot be a NULL pointer.这条消息的解读方式非常直接aclrtSynchronizeStream的stream参数被传入了空指针。消息文本本身已经精确到哪个函数、哪个参数因此排查 EH0008 时第一步永远是读完整条消息而不是只看错误码编号。与相邻空指针类错误码的区分ACL Errors 系列中还有两个容易混淆的空指针相关错误码需要放在一起对照错误码消息模板适用场景EH0002Argument %s must not be null.仅单个参数为空但消息中不包含函数名只报参数名见 error_code.jsonEH0008%s failed because %s cannot be a NULL pointer.单个参数为空且消息同时携带函数名与参数名EH0014%s failed because %s cannot be NULL pointers at the same time.多个指针参数不能同时为空至少需要其一非空见 error_code.json从消息粒度看EH0008 提供了最强的定位能力函数名 参数名 失败原因一次性给出是 ACL 侧带上报的参数空指针校验的标准错误码。源码级原理EH0008 是如何被触发的错误码常量定义在 ACL 公共日志与错误管理头文件 src/acl/common/log_inner.h 中EH0008 被定义为命名常量constexpr const char_t* const NULL_POINTER_FUNC_MSG EH0008;同一文件中还定义了相邻错误码常量INVALID_NULL_POINTER_MSG EH0002、INVALID_NULL_POINTER_AT_SAME_TIME_MSG EH0014等全部与error_code.json注册表一一对应。参数校验宏ACL_REQUIRES_NOT_NULL 系列EH0008 的真正触发点是一组以ACL_REQUIRES_NOT_NULL开头的校验宏。以最常用的 ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT 为例#define ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(val) \ do { \ if (UNLIKELY((val) nullptr)) { \ ACL_LOG_ERROR([Check][%s]param must not be null., #val); \ std::string funcName acl::AclErrorLogManager::GetFuncNameWithoutImplSuffix(__func__); \ acl::AclErrorLogManager::ReportInputError( \ acl::NULL_POINTER_FUNC_MSG, {func, param}, {funcName.c_str(), #val}); \ return ACL_ERROR_INVALID_PARAM; \ } \ } while (false)该宏的执行逻辑与 EH0008 消息模板严格对应可以拆解为四步判空检查入参val是否为nullptrUNLIKELY提示编译器该分支为冷路径不影响正常路径性能打印日志通过ACL_LOG_ERROR输出一条含参数名的错误日志上报错误调用AclErrorLogManager::ReportInputError携带错误码EH0008与两个字段func函数名和param参数名#val宏将变量名转为字符串字面量。其中函数名经过GetFuncNameWithoutImplSuffix处理剥离Impl后缀保证对外暴露的是aclrtSynchronizeStream这类公共 API 名而非内部实现名返回错误码返回ACL_ERROR_INVALID_PARAM非法参数调用方据此进行错误处理。仓库中还提供了该宏的多个变体覆盖不同上报与返回需求均位于 log_inner.h宏上报方式返回值ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(val)上报 EH0008函数名 参数名ACL_ERROR_INVALID_PARAMACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT_AND_FUNC_DESC(val, funcDesc)上报 EH0008可自定义函数描述ACL_ERROR_INVALID_PARAMACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT_WITH_PRAM_NAME(val, name)上报 EH0008可自定义参数名ACL_ERROR_INVALID_PARAMACL_REQUIRES_NOT_NULL_RET_NULL_INPUT_REPORT(val)上报 EH0008nullptrACL_REQUIRES_NOT_NULL_RET_INPUT_REPORT(val, ret)上报 EH0008自定义返回值retACL_REQUIRES_NOT_NULL(val)仅打日志不通过错误管理器上报ACL_ERROR_INVALID_PARAM其中WITH_INPUT_REPORT系列专门用于公共 API 入口的参数校验即产生 EH0008 报错的路径而ACL_REQUIRES_NOT_NULL不触发 EH0008 上报仅做内部防御性校验。调用链从公共 API 到 Impl 再到校验宏ACL 侧的公共 API 通过 X-Macro 机制统一注册。以本文示例中的aclrtSynchronizeStream为例在 src/acl/aclrt_impl/acl_rt_wrapper.h 的函数映射表中登记_(aclError, aclrtSynchronizeStream, (aclrtStream stream), (stream))公共入口aclrtSynchronizeStream会转发到内部实现aclrtSynchronizeStreamImpl实现在 src/acl/aclrt_impl/stream.cpp而空指针校验发生在更早的入口校验层。例如同文件中的aclrtDestroyStreamForcestream.cpp就是先执行校验再下发的典型形态ACL_LOG_INFO(start to execute aclrtDestroyStreamForce); ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(stream); // 空指针在这里触发 EH0008 ACL_REQUIRES_RTS_OK(rtStreamDestroyForce(static_castrtStream_t(stream)));完整触发链路可概括为用户调用公共 API如 aclrtDestroyStream → 转发至 xxxImpl见 acl_rt_wrapper.h 映射表 → ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(stream) 校验失败 → ACL_LOG_ERROR 打日志 ReportInputError(EH0008, func, param) → 返回 ACL_ERROR_INVALID_PARAM → 日志/错误管理中呈现 aclrtDestroyStream failed because stream cannot be a NULL pointer.哪些 API 会触发 EH0008搜索 src/acl/aclrt_impl 目录可以看到ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT系列校验宏被广泛用于各类公开 API 的入口覆盖 stream、context、memory、allocator、model_ri、label 等多个模块例如aclrtGetVersion三个输出参数majorVersion、minorVersion、patchVersion均做判空见 src/acl/aclrt_impl/acl_rt_impl_base.cpp内存分配相关接口src/acl/aclrt_impl/allocator.cpp、src/acl/aclrt_impl/memory.cpp中的stream参数上下文、标签、模型运行实例model_ri等模块中的stream/context参数。凡是接受输出型指针或句柄型指针的 ACL API理论上都存在触发 EH0008 的可能——这正是该错误码覆盖面的广度和排查价值所在。Runtime 侧的对应关系EE1004值得补充的是空指针校验不仅存在于 ACLHost 侧层。Runtime 核心侧维护了独立的错误码元数据表 src/runtime/core/inc/common/error_code_meta.h其中EE1004的消息模板与 EH0008 完全一致/* EE1004 - Invalid_Argument_Null_Pointer */ X(EE1004, EE1004, (func, param), %s failed because %s cannot be a NULL pointer. ErrorCodeEE1004.\n, DLOG_ERROR)两者的差异在于报错主体不同EH0008ACLAscendCL层参数校验失败错误发生在 Host 侧 API 入口EE1004Runtime 核心src/runtime下内部调用或跨层传入指针时校验失败消息末尾多出ErrorCodeEE1004.后缀并且消息以换行结束、可直接落入日志。实际排错时如果日志中看到的是EE1004说明问题发生在 Runtime 核心模块内部或驱动调用链上而非 ACL 公共 API 入口。两者的报错文本格式相同可共用本文的排查思路。排查与修复让调用代码符合 EH0008 的约束第一步完整读取报错消息定位函数与参数EH0008 的报错文本已自带定位信息。当你在终端或日志中看到aclrtSynchronizeStream failed because stream cannot be a NULL pointer.即可直接判定程序调用了aclrtSynchronizeStream且传入的stream参数为NULL。不要只记录错误码要把整条消息贴进问题单或检索条件。第二步检查指针生命周期与初始化引发空指针的常见根因包括未初始化/未创建调用aclrtSynchronizeStream前未调用aclrtCreateStream创建 stream或aclrtCreateStream失败后未检查返回值就继续使用输出参数指针未分配存储如aclrtGetVersion(major, minor, patch)中的变量确实已声明但传入了未取地址的值如传majorVersion而非majorVersion提前销毁stream/context/event 已被aclrtDestroyStream/aclrtDestroyContext销毁句柄悬空后被再次使用跨线程传递失效句柄在错误的作用域或线程中被使用。修复方向就是确保传入非空且有效的指针先创建、后使用、用前判空、用后延时销毁。第三步在代码中主动防御与诊断仓库的快速入门示例 example/0_quickstart/1_error_handling/main.cpp 演示了一套完整的触发预期失败并读取诊断信息的模式可以直接借鉴// 触发一个预期的非法参数错误输出型指针传 nullptr aclError expectedRet aclrtGetRunMode(nullptr); if (expectedRet ACL_SUCCESS) { WARN_LOG(Expected aclrtGetRunMode(nullptr) to fail, but it succeeded); } else { // 线程级错误诊断三件套 aclError peekError aclrtPeekAtLastError(ACL_RT_THREAD_LEVEL); // 窥视不消费 aclError lastError aclrtGetLastError(ACL_RT_THREAD_LEVEL); // 获取并消费 const char* recentErrMsg aclGetRecentErrMsg(); // 最近一次错误的可读消息 ERROR_LOG(Diagnostics: ret%d, peekErr%d, lastErr%d, recentErrMsg%s, static_castint32_t(expectedRet), static_castint32_t(peekError), static_castint32_t(lastError), SafeString(recentErrMsg)); }注意该示例演示的是aclrtGetRunMode(nullptr)触发空指针校验的场景——调用返回ACL_ERROR_INVALID_PARAM后通过aclrtPeekAtLastError/aclrtGetLastError读取线程级错误状态并通过aclGetRecentErrMsg拿到包含完整 EH0008 消息模板文本的字符串。这是实践中读取错误消息原文的官方推荐方式错误码用于程序分支判断消息文本用于人工排障。第四步按官方建议修正并回归依据 error_code.json 中登记的 Solution——Try again with a correct pointer argument修正指针后重新执行。建议在调用前后保持一致的防御习惯aclrtStream stream nullptr; if (aclrtCreateStream(stream) ! ACL_SUCCESS) { // 创建失败stream 可能仍为 nullptr禁止继续使用 return -1; } // ... 下发任务 ... if (aclrtSynchronizeStream(stream) ! ACL_SUCCESS) { // 此处 stream 必然非空 // 处理同步失败 } aclrtDestroyStream(stream);小结EH0008 的快速决策表维度内容错误码EH0008ACL Errors 类错误标题Invalid_Argument_Null_Pointer消息模板%s failed because %s cannot be a NULL pointer.占位符 1出错阶段或 API 名称如aclrtSynchronizeStream占位符 2出错参数名如stream返回码ACL_ERROR_INVALID_PARAM触发宏ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT系列见 src/acl/common/log_inner.h注册表src/dfx/error_manager/error_code.jsonRuntime 侧对应码EE1004见 src/runtime/core/inc/common/error_code_meta.h官方建议使用正确的指针参数重试延伸阅读错误码全览ACL Errors 索引、docs/zh/error_code_ref/ACL-Errors/README.md相邻错误码EH0002单参数为空、EH0014参数不能同时为空错误消息实现src/acl/common/log_inner.h、src/acl/common/log_inner.cpp错误处理示例工程example/0_quickstart/1_error_handling/main.cpp异步错误码解读方法论如何获取和解读Runtime异步错误码【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考