长稳测试的时候,偶现CppCrash崩溃,每次的崩溃栈不同,复现的场景不明确。查看多个崩溃日志都有出现SIGSEGV(SEGV_MAPERR)@0x0000000000000000 probably caused by NULL pointer dereference报错,其中之一的报错信息如下:
Generated by HiviewDFX@OpenHarmony ================================================================ Device info:HUAWEI Mate 60 Pro Build info:ALN-AL00 5.0.0.150(SP8C00E150R4P30log) Fingerprint:xxxxxxxxx Module name:com.example.application Version:2.8.5 VersionCode:30 PreInstalled:No Foreground:No Timestamp:2025-04-30 14:17:03.643 Pid:42378 Uid:20020210 Process name:com.example.application Process life time:18446744073709405886s Reason:Signal:SIGSEGV(SEGV_MAPERR)@0x0000000000000007 probably caused by NULL pointer dereference Fault thread info: Tid:42378, Name:m.example.application #00 pc 0000000000135dc8 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #01 pc 0000000000135d68 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #02 pc 00000000001397c0 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #03 pc 000000000012b0d8 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #04 pc 000000000012aa78 /data/storage/el1/bundle/libs/arm64/libnet.so(doCallback(napi_env__*, napi_status, void*)+1584)(91a0f067f914ed44654e1191fccc295e60882cb0) #05 pc 00000000000704f4 /system/lib64/platformsdk/libace_napi.z.so(NativeSafeAsyncWork::ProcessAsyncHandle()+596)(85e70f1f5cf0e81468ec141fc2f4922c) #06 pc 0000000000016de4 /system/lib64/platformsdk/libuv.so(uv__async_io+352)(81fe2b78ed1df8447a6c4e51c5f644e2) #07 pc 0000000000028840 /system/lib64/platformsdk/libuv.so(uv__io_poll+1016)(81fe2b78ed1df8447a6c4e51c5f644e2) #08 pc 00000000000173cc /system/lib64/platformsdk/libuv.so(uv_run+408)(81fe2b78ed1df8447a6c4e51c5f644e2) #09 pc 000000000007f250 /system/lib64/platformsdk/libruntime.z.so(OHOS::AbilityRuntime::OHOSLoopHandler::OnTriggered()+140)(17e438b05b67ccb9c7eb96e54ed833e5) #10 pc 0000000000020430 /system/lib64/chipset-pub-sdk/libeventhandler.z.so(770d0cd78402a5ad1ced37fad50c5707) #11 pc 000000000001bdb4 /system/lib64/chipset-pub-sdk/libeventhandler.z.so(OHOS::AppExecFwk::EventHandler::DistributeEvent(std::__h::unique_ptr<OHOS::AppExecFwk::InnerEvent, void (*)(OHOS::AppExecFwk::InnerEvent*)> const&)+1140)(770d0cd78402a5ad1ced37fad50c5707)
CppCrash(进程崩溃)是指C/C++运行时崩溃。目前主要支持崩溃异常信号SIGBUS、SIGFPE、SIGSEGV、SIGSTKFLT、SIGSYS、SIGILL、SIGTRAP、SIGABRT的处理。可以通过FaultLogger模块获取崩溃日志。
崩溃日志报错中空指针解引用NULL pointer dereference表现形式一般为:
定位该类型问题一般尝试以下几种方法:
pc 0000000000135dc8 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #01 pc 0000000000135d68 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #02 pc 00000000001397c0 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #03 pc 000000000012b0d8 /data/storage/el1/bundle/libs/arm64/libnet.so(91a0f067f914ed44654e1191fccc295e60882cb0) #04 pc 000000000012aa78 /data/storage/el1/bundle/libs/arm64/libnet.so(doCallback(napi_env__*, napi_status, void*)+1584)(91a0f067f914ed44654e1191fccc295e60882cb0)
void doCallback(napi_env env, napi_status status, void *data) {
if (env == nullptr || data == nullptr) {
LOGE("Invalid env or data");
return;
}
// ...
} {
"apiType": "stageMode",
"buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": ["-DCMAKE_BUILD_TYPE=RelWithDebInfo"],
"cppFlags": "",
}
},
// ...
} "buildOptionSet": [
{
"name": "debug",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
}
}
},
"nativeLib": {
"debugSymbol": {
"strip": false,
"exclude": []
}
}
},
], [root@ncn4b-partnervectorservice-33-83-97 arm64-v8a]# file libnet.so libnet.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=9d075a569e007bc6e4ea25f2f96be548724b4aef, with debug_info, not stripped
llvm-addr2line -Cipe LocalPath/libnet.so 000000000012aa78
napi_call_function(env, nullptr, callback, 1, &returnValue, &tempValue);
说明是napi_call_function在调用ArkTS函数指针的时候,回调函数指针可能被其他线程释放了才导致的踩空。
但是从上层传下来的函数制造者却没有创建强引用napi_ref保留。所以当GC回收了ArkTS的回调函数资源后,使用该ArkTS回调函数可能在Native执行napi_call_function前就已经是空指针了,最后导致空指针解引用。
// 异步工作Native流程
static napi_value StartAsyncWork(napi_env env, napi_callback_info info)
{
// 从模块数据中获取函数引用
ModuleData* moduleData = nullptr;
napi_get_instance_data(env, (void**)&moduleData);
if (moduleData == nullptr || moduleData->arktsFuncRef == nullptr) {
napi_throw_error(env, nullptr, "请先注册ArkTS函数");
return nullptr;
}
// 创建新的工作数据
AsyncWorkData* workData = new AsyncWorkData();
workData->env = env;
// 为异步工作创建新的函数引用
napi_value arktsFunc;
if (napi_get_reference_value(env, moduleData->arktsFuncRef, &arktsFunc) != napi_ok) {
delete workData;
napi_throw_error(env, nullptr, "获取注册的函数失败");
return nullptr;
}
// 创建新的引用给异步工作使用
if (napi_create_reference(env, arktsFunc, 1, &workData->arktsFuncRef) != napi_ok) {
delete workData;
napi_throw_error(env, nullptr, "为异步工作创建函数引用失败");
return nullptr;
}
// 创建异步工作
napi_async_work asyncWork;
napi_value workName;
napi_create_string_utf8(env, "MyProc", NAPI_AUTO_LENGTH, &workName);
if (napi_create_async_work(env, nullptr, workName, ExecuteWork, doCallback, workData, &asyncWork) != napi_ok) {
napi_delete_reference(env, workData->arktsFuncRef);
delete workData;
napi_throw_error(env, nullptr, "创建异步工作失败");
return nullptr;
}
// 排队执行异步工作
if (napi_queue_async_work(env, asyncWork) != napi_ok) {
napi_delete_async_work(env, asyncWork);
napi_delete_reference(env, workData->arktsFuncRef);
delete workData;
napi_throw_error(env, nullptr, "排队异步工作失败");
return nullptr;
}
OH_LOG_INFO(LOG_APP, "异步工作已启动");
napi_value result;
napi_get_undefined(env, &result);
return result;
} // 异步工作完成回调(在主线程/JS线程中执行)
void doCallback(napi_env env, napi_status status, void* data)
{
AsyncWorkData* workData = static_cast<AsyncWorkData*>(data);
if (status != napi_ok || workData == nullptr) {
OH_LOG_ERROR(LOG_APP, "异步工作完成回调出错");
return;
}
// 安全地调用ArkTS函数
if (workData->arktsFuncRef != nullptr) {
napi_handle_scope scope;
napi_status status;
// 创建作用域
if (napi_open_handle_scope(env, &scope) != napi_ok) {
OH_LOG_ERROR(LOG_APP, "打开handle scope失败");
// 清理工作数据
if (workData->arktsFuncRef != nullptr) {
napi_delete_reference(env, workData->arktsFuncRef);
}
delete workData;
return;
}
napi_value arktsFunc;
status = napi_get_reference_value(env, workData->arktsFuncRef, &arktsFunc);
if (status == napi_ok && arktsFunc != nullptr) {
// 创建要传递给ArkTS函数的参数,本例为字符串
napi_value argv[1];
napi_create_string_utf8(env, workData->resultMessage.c_str(), NAPI_AUTO_LENGTH, &argv[0]);
// 调用ArkTS函数
napi_value global;
napi_get_global(env, &global);
napi_value result;
if (napi_call_function(env, global, arktsFunc, 1, argv, &result) == napi_ok) {
OH_LOG_INFO(LOG_APP, "成功调用ArkTS回调函数,消息: %{public}s",
workData->resultMessage.c_str());
} else {
OH_LOG_ERROR(LOG_APP, "调用ArkTS函数失败");
}
} else {
OH_LOG_ERROR(LOG_APP, "获取ArkTS函数引用失败");
}
// 关闭作用域
napi_close_handle_scope(env, scope);
}
} 完整示例参考如下:
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(SQI202505101216105442012)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_library(entry SHARED napi_init.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libuv.so) /*
* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
*/
#include "napi/native_api.h"
#include <thread>
#include "hilog/log.h"
#include <uv.h>
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0x3200 // 全局domain宏,标识业务领域
#define LOG_TAG "MY_TAG" // 全局tag宏,标识模块日志tag
// 异步工作数据结构
struct AsyncWorkData {
napi_env env = nullptr;
napi_ref arktsFuncRef = nullptr; // 保存ArkTS函数的引用
std::string resultMessage; // 要传递给ArkTS的结果
};
// 模块全局数据
struct ModuleData {
napi_ref arktsFuncRef = nullptr;
};
// 异步工作执行函数(在工作线程中执行)
void ExecuteWork(napi_env env, void* data)
{
AsyncWorkData* workData = static_cast<AsyncWorkData*>(data);
// 模拟一些耗时操作
for (int i = 0; i < 3; i++) {
OH_LOG_INFO(LOG_APP, "耗时异步流程执行中... %{public}d", i);
// 模拟工作耗时操作
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
// 准备要传递给ArkTS的消息
workData->resultMessage = "来自Native层的异步完成消息,时间戳: " +
std::to_string(uv_hrtime() / 1000000);
}
// 异步工作完成回调(在主线程/JS线程中执行)
void doCallback(napi_env env, napi_status status, void* data)
{
AsyncWorkData* workData = static_cast<AsyncWorkData*>(data);
if (status != napi_ok || workData == nullptr) {
OH_LOG_ERROR(LOG_APP, "异步工作完成回调出错");
return;
}
// 安全地调用ArkTS函数
if (workData->arktsFuncRef != nullptr) {
napi_handle_scope scope;
napi_status status;
// 创建作用域
if (napi_open_handle_scope(env, &scope) != napi_ok) {
OH_LOG_ERROR(LOG_APP, "打开handle scope失败");
// 清理工作数据
if (workData->arktsFuncRef != nullptr) {
napi_delete_reference(env, workData->arktsFuncRef);
}
delete workData;
return;
}
napi_value arktsFunc;
status = napi_get_reference_value(env, workData->arktsFuncRef, &arktsFunc);
if (status == napi_ok && arktsFunc != nullptr) {
// 创建要传递给ArkTS函数的参数,本例为字符串
napi_value argv[1];
napi_create_string_utf8(env, workData->resultMessage.c_str(), NAPI_AUTO_LENGTH, &argv[0]);
// 调用ArkTS函数
napi_value global;
napi_get_global(env, &global);
napi_value result;
if (napi_call_function(env, global, arktsFunc, 1, argv, &result) == napi_ok) {
OH_LOG_INFO(LOG_APP, "成功调用ArkTS回调函数,消息: %{public}s",
workData->resultMessage.c_str());
} else {
OH_LOG_ERROR(LOG_APP, "调用ArkTS函数失败");
}
} else {
OH_LOG_ERROR(LOG_APP, "获取ArkTS函数引用失败");
}
// 关闭作用域
napi_close_handle_scope(env, scope);
}
}
// 注册ArkTS函数的Native方法
static napi_value RegisterArkTSFunction(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc < 1) {
napi_throw_error(env, nullptr, "需要传入ArkTS函数作为参数");
return nullptr;
}
napi_valuetype valuetype;
napi_typeof(env, args[0], &valuetype);
if (valuetype != napi_function) {
napi_throw_type_error(env, nullptr, "参数必须是一个函数");
return nullptr;
}
// 获取模块数据
ModuleData* moduleData = nullptr;
napi_get_instance_data(env, (void**)&moduleData);
if (moduleData == nullptr) {
moduleData = new ModuleData();
napi_set_instance_data(env, moduleData, [](napi_env env, void* data, void* hint) {
ModuleData* moduleData = static_cast<ModuleData*>(data);
if (moduleData && moduleData->arktsFuncRef) {
napi_delete_reference(env, moduleData->arktsFuncRef);
}
delete moduleData;
}, nullptr);
} else {
// 如果已经注册过函数,先清理旧的引用
if (moduleData->arktsFuncRef != nullptr) {
napi_delete_reference(env, moduleData->arktsFuncRef);
moduleData->arktsFuncRef = nullptr;
}
}
// 创建对ArkTS函数的强引用,防止被GC
napi_status status = napi_create_reference(env, args[0], 1, &moduleData->arktsFuncRef);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "创建函数引用失败");
return nullptr;
}
OH_LOG_INFO(LOG_APP, "ArkTS函数注册成功");
napi_value result;
napi_get_undefined(env, &result);
return result;
}
// 异步工作Native流程
static napi_value StartAsyncWork(napi_env env, napi_callback_info info)
{
// 从模块数据中获取函数引用
ModuleData* moduleData = nullptr;
napi_get_instance_data(env, (void**)&moduleData);
if (moduleData == nullptr || moduleData->arktsFuncRef == nullptr) {
napi_throw_error(env, nullptr, "请先注册ArkTS函数");
return nullptr;
}
// 创建新的工作数据
AsyncWorkData* workData = new AsyncWorkData();
workData->env = env;
// 为异步工作创建新的函数引用
napi_value arktsFunc;
if (napi_get_reference_value(env, moduleData->arktsFuncRef, &arktsFunc) != napi_ok) {
delete workData;
napi_throw_error(env, nullptr, "获取注册的函数失败");
return nullptr;
}
// 创建新的引用给异步工作使用
if (napi_create_reference(env, arktsFunc, 1, &workData->arktsFuncRef) != napi_ok) {
delete workData;
napi_throw_error(env, nullptr, "为异步工作创建函数引用失败");
return nullptr;
}
// 创建异步工作
napi_async_work asyncWork;
napi_value workName;
napi_create_string_utf8(env, "MyProc", NAPI_AUTO_LENGTH, &workName);
if (napi_create_async_work(env, nullptr, workName, ExecuteWork, doCallback, workData, &asyncWork) != napi_ok) {
napi_delete_reference(env, workData->arktsFuncRef);
delete workData;
napi_throw_error(env, nullptr, "创建异步工作失败");
return nullptr;
}
// 排队执行异步工作
if (napi_queue_async_work(env, asyncWork) != napi_ok) {
napi_delete_async_work(env, asyncWork);
napi_delete_reference(env, workData->arktsFuncRef);
delete workData;
napi_throw_error(env, nullptr, "排队异步工作失败");
return nullptr;
}
OH_LOG_INFO(LOG_APP, "异步工作已启动");
napi_value result;
napi_get_undefined(env, &result);
return result;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "registerArkTSFunction", nullptr, RegisterArkTSFunction, nullptr, nullptr, nullptr, napi_default, nullptr },
{ "startAsyncWork", nullptr, StartAsyncWork, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void*)0),
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
napi_module_register(&demoModule);
} export const registerArkTSFunction: (callback: (message: string) => void) => void; export const startAsyncWork: () => void;
import testNapi from 'libentry.so';
// 要传递给Native层的回调函数
function myArkTSFunction(message: string): void {
console.info('ArkTS收到Native消息: ' + message);
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
aboutToAppear(): void {
this.registerCallbackToNative();
}
build() {
Row() {
Column() {
Text(this.message)
.fontSize(20)
.margin(10)
Button('触发异步工作')
.onClick(() => {
this.triggerAsyncWork();
this.message = '异步工作已触发';
})
.margin(10)
}
.width('100%');
}
.height('100%');
}
// 注册回调函数到Native层
registerCallbackToNative(): void {
try {
testNapi.registerArkTSFunction(myArkTSFunction);
console.info('ArkTS函数注册成功');
} catch (error) {
console.error('注册ArkTS函数失败: ' + error);
}
}
// 触发Native层的异步工作
triggerAsyncWork(): void {
try {
testNapi.startAsyncWork();
console.info('已触发Native异步工作');
} catch (error) {
console.error('触发异步工作失败: ' + error);
}
}
}