目录

How do I manage the JSVM_CallbackStruct lifecycle?

Question

  1. The application crashes when the JavaScript function created using OH_JSVM_CreateFunction is called.

    You need to specify the time to release the memory allocated for JSVM_CallbackStruct using new().

Possible Causes

The lifecycle of JSVM_CallbackStruct is not correctly managed. An example of the error code is as follows:

JSVM_Value CreateFunction(JSVM_Env env) {
    JSVM_CallbackStruct callbackStruct;
    callbackStruct.data = nullptr;
    callbackStruct.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
        return nullptr;
    };

    JSVM_Value result = nullptr;
    OH_JSVM_CreateFunction(env, "foo", JSVM_AUTO_LENGTH, &callbackStruct, &result);
    return result;
}
void SomeFunction() {
    char stack[] = "hello world";
}

The application crashes when the following code is executed:

// ...

auto func = CreateFunction(env);
SomeFunction();

JSVM_Value undef = nullptr;
OH_JSVM_GetUndefined(env, &undef);

JSVM_Value result;
OH_JSVM_CallFunction(env, undef, func, 0, nullptr, &result);

// ...

When OH_JSVM_CallFunction is called, callbackStruct is a variable on the stack, and OH_JSVM_CreateFunction receives the stack memory address (&callbackStruct). After SomeFunction is called, the stack memory is modified. When OH_JSVM_CallFunction is called, the callback function in JSVM_CallbackStruct is executed. Because the memory of JSVM_CallbackStruct has been modified, invalid memory access causes the application to crash.

Answer

If the JavaScript function created using OH_JSVM_CreateFunction needs to be used across functions, the memory for JSVM_CallbackStruct must be applied for from the heap and cannot be released before the JavaScript function becomes invalid. The memory of JSVM_CallbackStruct can be released by the garbage collection mechanism of the VM. You can call OH_JSVM_AddFinalizer to set the Finalize method for the JavaScript function. When the JavaScript function is garbage collected, the Finalize method is called and JSVM_CallbackStruct is released. Refer to the code snippet below:

JSVM_Value CreateFunction(JSVM_Env env) {
    JSVM_Callback cb = new JSVM_CallbackStruct;
    cb->data = nullptr;
    cb->callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value { return nullptr; };

    JSVM_Value result = nullptr;
    OH_JSVM_CreateFunction(env, "foo", JSVM_AUTO_LENGTH, cb, &result);
    OH_JSVM_AddFinalizer(
        env, result, reinterpret_cast<void *>(cb),
        [](JSVM_Env env, void *data, void *hint) -> void { 
            delete static_cast<JSVM_Callback>(data);
        }, nullptr, nullptr);

    return result;
}