【问题标题】:Calling V8 function causes access violation调用 V8 函数导致访问冲突
【发布时间】:2013-06-20 20:41:24
【问题描述】:

我有一个全局事件管理器,允许您使用 lambdas 侦听string 事件名称。

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

现在,我也想从 JavaScript 注册事件。因此,我写了这个回调。

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();
}

触发事件后,应用程序会因访问冲突而崩溃。我的想法是函数对象此时不再有效,或者是 JavaScript 范围问题。但我想不通。

什么导致访问冲突以及如何克服它?

【问题讨论】:

  • 什么指令导致访问冲突?
  • @Gonmator 错误位于function-&gt;Call(function, 0, NULL);这一行。

标签: javascript c++ function access-violation v8


【解决方案1】:

我相信这里有几个潜在的问题。

首先,在ModuleScript::jsOn() 终止后,您没有使用持久句柄来保存 JavaScript 函数。当您的事件处理程序被调用时,该函数可能已经消失了。考虑将callback 设为持久句柄。

其次,您的事件处理程序需要在调用 JavaScript 函数之前输入适当的 V8 上下文。根据您的架构,可能还需要显式锁定并进入 V8 隔离。

第三(这在您的特定场景中可能不是问题),您需要管理 V8 隔离的生命周期。如果您的事件管理器在后台线程上触发事件,您必须确保您的事件处理程序以某种方式阻止隔离从另一个线程中释放。不幸的是,这是 V8 API 没有提供太多帮助的领域。

第四,为防止泄漏,您的事件处理程序应在调用函数后处理持久函数句柄。

祝你好运!

【讨论】:

  • 我在 lambda 中使用了 [=] 捕获子句和 v8::HandleScope scope(v8::Isolate::GetCurrent()); persistent-&gt;Call(persistent, 0, NULL);
  • 对,我忘了句柄范围。很高兴你成功了!
猜你喜欢
  • 1970-01-01
  • 2019-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
相关资源
最近更新 更多