skills/oh-memory-leak-detection/SKILL.md
--- name: memory-leak-detection description: Detect 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. --- # NAPI Memory Leak Detection ## Quick Start Functions working
npx skillsauth add openharmonyinsight/openharmony-skills skills/oh-memory-leak-detectionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Functions working with napi_value need scope management to prevent leaks.
Detection Checklist:
napi_value?napi_value& parameter?napi_create_*?napi_value variables?HandleScope?For detailed background on JS/C++ memory management, see references/background.md
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);
}
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;
}
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);
}
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
}
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");
}
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);
}
napi_value FunctionName(napi_env env, /* parameters */) {
HandleEscape handleEscape(env);
// ... function body ...
return handleEscape.Escape(result);
}
void FunctionName(napi_env env, napi_value& output, /* parameters */) {
HandleScope handleScope(env);
// ... function body ...
output = value;
}
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 that commonly return napi_value and need scope management:
Create Functions:
Convert2JSValueCreateJsAppStateData, CreateJsAbilityStateData, CreateJsProcessDataCreateJsMissionInfo, CreateJsWant, CreateJsWantParamsCreateJsErrorWrap Functions:
WrapVoidToJS, WrapStringToJS, WrapInt32ToJSWrapConfiguration, WrapElementNameWrapWant, WrapWantAgent, WrapWantParamsWrapAbilityResultCustom Functions:
Any function with Create or Wrap in the name that returns napi_value
export ASAN_OPTIONS=detect_leaks=1
./build.sh --product-name <product> --build-target ability_runtime --ccache
// Call function repeatedly to detect memory growth
for (int i = 0; i < 10000; i++) {
auto result = FunctionToTest(env);
}
// Monitor memory usage for continuous growth
Wiki: https://wiki.huawei.com/domains/1048/wiki/8/WIKI202511108963910
Workflow:
napi_value to parent scopeHandleScope when receiving napi_value& as output parameternapi_create_* calls create JS objects that need scope managementHandleScopenapi_value variables must be managednapi_value need HandleEscapenapi_value used in expressions needs scope managementThese 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_uint64Strings:
napi_create_string_utf8, napi_create_string_utf16, napi_create_string_latin1Objects:
napi_create_object, napi_create_array, napi_create_array_with_lengthFunctions and Classes:
napi_create_function, napi_new_instancetesting
--- name: ohos-req-value-decision description: Use after review meeting to record decision and route to next step. Triggers: 评审决策纪要, 评审结论回流, value decision, 评审接纳, 评审不接纳, 评审退回, 下次重新上会. Do NOT use for feature baseline (ohos-req-feature-baseline), review gate checks (ohos-req-review-gate), or IR generation (ohos-req-feature-to-ir). metadata: author: openharmony scope: common stage: requirements capability: value-decision version: 0.3.0 status: draft tags: - sdd - requirements
development
Use when converting an OpenHarmony requirement document, spec, or design proposal into an OpenHarmony review slide deck (需求评审 / 需求变更评审 / 设计评审 PPTX) — produces the fixed OpenHarmony-branded review-deck structure (OH logo on every page) with architecture/flow diagrams and field tables. Triggers on "需求评审PPT", "需求变更评审", "把需求文档转成评审PPT", "spec转评审PPT", "requirement/spec to review deck". NOT for arbitrary or generic slide decks unrelated to OpenHarmony requirement/design review.
testing
Use when performing the Phase 0 Step 0.5 Review Ready Gate on a 04-feature.md, especially when the user says "evaluate gate", "review readiness", "feature ready?", "should we generate IR", or when the ohos-req-intake-orchestration main session needs a structured Ready / Conditional Ready / Not Ready judgment instead of doing the check inline. Reads 01-04, runs seven fixed checks plus a conditional-items check, and returns a machine-readable JSON summary plus a human-readable table that the main session can route on. Do NOT use for feature baseline generation (ohos-req-feature-baseline), value decision recording (ohos-req-value-decision), or IR generation (ohos-req-feature-to-ir).
testing
--- name: ohos-req-requirement-intake description: Use when importing an OHOS requirement into Phase 0.1, especially for 01-requirement.md, requirement intake, background, user value, scenarios, scope, FR/NFR, affected modules, or priority. Triggers: 需求导入, 01-requirement, 需求基线, RR单号. Do NOT use for feasibility analysis (ohos-req-feasibility-analysis), architecture decision (ohos-req-arch-decision), or feature baseline (ohos-req-feature-baseline). metadata: author: openharmony scope: common