NAPI Memory Leak Detection
SkillDocs & knowledgeDetect and fix NAPI memory leaks in OpenHarmony Ability Runtime. Use when reviewing NAPI code for memory leaks, especially functions that: (1) Return napi_value, (2) Have napi_value& parameters, (3) Call napi_create_* functions, (4) Set properties with temporary napi_value variables, (5) Work in async callbacks. See references/background.md for detailed memory management principles.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the NAPI Memory Leak Detection skill
What this skill tells your AI
The instructions your AI receives, as published by openharmonyinsight/openharmony-skills in skills/oh-memory-leak-detection/SKILL.md and read by ahel’s review.
Quick Start
Functions working with napi_value need scope management to prevent leaks.
Detection Checklist:
- Function returns
napi_value? - Function has
napi_value¶meter? - Function calls
napi_create_*? - Creates temporary
napi_valuevariables? - Async callback without
HandleScope? - Gets napi_value from other functions?
For detailed background on JS/C++ memory management, see references/background.md
Common Patterns
Pattern 1: Function Returns napi_value
Use HandleEscape when returning napi_value to parent scope.
// ❌ LEAK
napi_value Func(napi_env env) {
napi_value result = nullptr;
napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &result);
return result;
}
// ✅ FIXED
napi_value Func(napi_env env) {
HandleEscape handleEscape(env);
napi_value result = nullptr;
napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &result);
return handleEscape.Escape(result);
}
Pattern 2: Function with napi_value& Parameter
Use HandleScope when receiving napi_value& as output parameter.
// ❌ LEAK
void Func(napi_env env, napi_value& objValue) {
napi_value temp = nullptr;
napi_new_instance(env, cls, 0, nullptr, &temp);
objValue = temp;
}
// ✅ FIXED
void Func(napi_env env, napi_value& objValue) {
HandleScope handleScope(env);
napi_value temp = nullptr;
napi_new_instance(env, cls, 0, nullptr, &temp);
objValue = temp;
}
Pattern 3: Property Setting with Temporaries
Temporary napi_value variables created during property setting need management.
// ❌ LEAK
napi_value CreateInfo(napi_env env, const Data& data) {
napi_value obj = nullptr;
napi_create_object(env, &obj);
napi_value name = CreateJsValue(env, data.name); // Leak
napi_value pid = CreateJsValue(env, data.pid); // Leak
napi_set_named_property(env, obj, "name", name);
napi_set_named_property(env, obj, "pid", pid);
return obj;
}
// ✅ FIXED
napi_value CreateInfo(napi_env env, const Data& data) {
HandleEscape handleEscape(env);
napi_value obj = nullptr;
napi_create_object(env, &obj);
napi_value name = CreateJsValue(env, data.name);
napi_value pid = CreateJsValue(env, data.pid);
napi_set_named_property(env, obj, "name", name);
napi_set_named_property(env, obj, "pid", pid);
return handleEscape.Escape(obj);
}
Pattern 4: Getting napi_value from Other Functions
When calling functions that return napi_value, the returned value needs scope management.
// ❌ LEAK
bool Func(napi_env env) {
auto executorNapiVal = jsObj_->GetNapiValue();
// executorNapiVal escapes when function returns
}
// ✅ FIXED
bool Func(napi_env env) {
HandleScope handleScope(env);
auto executorNapiVal = jsObj_->GetNapiValue();
// Use executorNapiVal within this scope
}
Pattern 5: Async Callbacks
Async tasks need their own HandleScope to manage napi_value created in callbacks.
// ❌ LEAK
void AsyncBad(napi_env env, napi_value callback) {
std::thread([env, callback]() {
napi_value result = nullptr;
napi_create_string_utf8(env, "async result", NAPI_AUTO_LENGTH, &result);
}).detach();
}
// ✅ FIXED
void AsyncGood(napi_env env, napi_value callback, std::shared_ptr<AbilityHandler> handler) {
std::string data = "async result";
auto task = [env, callback, data]() {
HandleScope handleScope(env);
napi_value result = nullptr;
napi_create_string_utf8(env, data.c_str(), NAPI_AUTO_LENGTH, &result);
napi_call_function(env, callback, 1, &result, nullptr);
};
handler->PostTask(task, "AsyncTask");
}
Pattern 6: napi_value Used in Conditional Expressions
When napi_value is used in conditional checks, it needs scope management.
// ❌ LEAK
napi_value Func1(napi_env env) {
napi_value xxx = nullptr;
napi_create_double(env, 42.0, &xxx);
return xxx;
}
bool TestFunc(napi_env env) {
if (Func1(env) == someValue) {
// Func1 returns napi_value that leaks
}
return true;
}
// ✅ FIXED
napi_value Func1(napi_env env) {
HandleEscape handleEscape(env);
napi_value xxx = nullptr;
napi_create_double(env, 42.0, &xxx);
return handleEscape.Escape(xxx);
}
Quick Fix Templates
Template 1: Function Returning napi_value
napi_value FunctionName(napi_env env, /* parameters */) {
HandleEscape handleEscape(env);
// ... function body ...
return handleEscape.Escape(result);
}
Template 2: Function with napi_value& Parameter
void FunctionName(napi_env env, napi_value& output, /* parameters */) {
HandleScope handleScope(env);
// ... function body ...
output = value;
}
Template 3: Function Creating Multiple Properties
napi_value CreateJsObject(napi_env env, const DataType& data) {
HandleEscape handleEscape(env);
napi_value obj = nullptr;
napi_create_object(env, &obj);
napi_value prop1 = CreateJsValue(env, data.field1);
napi_value prop2 = CreateJsValue(env, data.field2);
napi_set_named_property(env, obj, "prop1", prop1);
napi_set_named_property(env, obj, "prop2", prop2);
return handleEscape.Escape(obj);
}
Functions to Review
Functions that commonly return napi_value and need scope management:
Create Functions:
Convert2JSValueCreateJsAppStateData,CreateJsAbilityStateData,CreateJsProcessDataCreateJsMissionInfo,CreateJsWant,CreateJsWantParamsCreateJsError
Wrap Functions:
WrapVoidToJS,WrapStringToJS,WrapInt32ToJSWrapConfiguration,WrapElementNameWrapWant,WrapWantAgent,WrapWantParamsWrapAbilityResult
Custom Functions:
Any function with Create or Wrap in the name that returns napi_value
Testing
ASAN Detection
export ASAN_OPTIONS=detect_leaks=1
./build.sh --product-name <product> --build-target ability_runtime --ccache
Manual Testing
// Call function repeatedly to detect memory growth
for (int i = 0; i < 10000; i++) {
auto result = FunctionToTest(env);
}
// Monitor memory usage for continuous growth
XTS Memory Leak Detection
Wiki: https://wiki.huawei.com/domains/1048/wiki/8/WIKI202511108963910
Workflow:
- Configure device
- Flash version
- Sync code and push diff
- Compile .so files
- Push .so and replace with symbol version
- Enable detection switch and restart device
- Capture logs
- Extract leak stack traces
Key Principles
- HandleEscape when returning
napi_valueto parent scope HandleScopewhen receivingnapi_value&as output parameter- All
napi_create_*calls create JS objects that need scope management - Async callbacks need their own
HandleScope - Temporary
napi_valuevariables must be managed - Functions returning
napi_valueneedHandleEscape napi_valueused in expressions needs scope management
Common napi_create_* Functions
These functions create JS objects and return napi_value:
Primitives:
napi_create_int32,napi_create_uint32,napi_create_int64napi_create_double,napi_create_bigint_int64,napi_create_bigint_uint64
Strings:
napi_create_string_utf8,napi_create_string_utf16,napi_create_string_latin1
Objects:
napi_create_object,napi_create_array,napi_create_array_with_length
Functions and Classes:
napi_create_function,napi_new_instance
Additional Resources
- Background knowledge: references/background.md
- Detailed cases: references/detailed-cases.md
- Contact: Chen Rui (00951372), Deng Wenjun (00850728) for uncertain cases
Signals
- GitHub stars
- 34
- Forks
- 7
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
memory-leak-detection- Source
- github.com/openharmonyinsight/openharmony-skills