Calling V8 function causes access violation

2019-08-07 19:07发布

I have a global event manager, allowing you to listen with lambdas to string event names.

// somewhere in the ModuleScript class
Event->Listen("WindowResize", [=]{
    // ...
});

Now, I want to register to events from JavaScript, too. Therefore, I wrote this callback.

v8::Handle<v8::Value> ModuleScript::jsOn(const v8::Arguments& args)
{
    // get pointer to class since we're in a static method
    ModuleScript *module = (ModuleScript*)HelperScript::Unwrap(args.Data());

    // get event name we want to register to from arguments
    if(args.Length() < 1 || !args[0]->IsString())
        return v8::Undefined();
    string name = *v8::String::Utf8Value(args[0]);

    // get callback function from arguments
    if(args.Length() < 2 || !args[1]->IsFunction())
        return v8::Undefined();
    v8::Handle<v8::Function> callback =
        v8::Local<v8::Function>::Cast(args[1]->ToObject());

    // register event on global event manager
    module->Event->Listen(name, [=]{
        // create persistent handle so that function stays valid
        // maybe this doesn't work, I don't know
        v8::Persistent<v8::Function> function =
            v8::Persistent<v8::Function>::New(args.GetIsolate(), callback);
        // execute callback function
        // causes the access violation
        function->Call(function, 0, NULL);
    });

    return v8::Undefined();
}

When the event is triggered, the application crashes with a access violation. My thoughts are that either the function object isn't valid at this time anymore, or it is a JavaScript scope issue. But I couldn't figure it out.

What causes the access violation and how to overcome it?

1条回答
男人必须洒脱
2楼-- · 2019-08-07 19:29

I believe there are several potential issues here.

First, you're not using a persistent handle to hold the JavaScript function after ModuleScript::jsOn() terminates. By the time your event handler is invoked, the function might be gone. Consider making callback a persistent handle.

Second, your event handler needs to enter an appropriate V8 context before calling the JavaScript function. Depending on your architecture, explicitly locking and entering the V8 isolate may be required as well.

Third (and this may not be an issue in your specific scenario), you need to manage the lifetime of the V8 isolate. If your event manager fires events on background threads, you have to make sure your event handler somehow prevents the isolate from being disposed from another thread. Unfortunately this is one area where the V8 API doesn't provide much help.

Fourth, to prevent a leak, your event handler should dispose the persistent function handle after invoking the function.

Good luck!

查看更多
登录 后发表回答