I’m trying to call a registered JS function when a c++ callback is called, but I’m getting a segfault for what I assume is a scoping issue.
Handle<Value> addEventListener( const Arguments& args ) {
HandleScope scope;
if (!args[0]->IsFunction()) {
return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
}
Persistent<Function> fn = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
Local<Number> num = Number::New(registerListener(&callback, &fn));
scope.Close(num);
}
When an event happens, the following method is called. I’m assuming that this probably happens on another thread to which V8 is executing JS.
void callback(int event, void* context ) {
HandleScope scope;
Local<Value> args[] = { Local<Value>::New(Number::New(event)) };
Persistent<Function> *func = static_cast<Persistent<Function> *>(context);
(* func)->Call((* func), 1, args);
scope.Close(Undefined());
}
This causes a Segmentation fault: 11. Note that if I call the callback function directly with a reference to Persistent from addEventListener(), it executes the function correctly.
I’m assuming that I need a Locker or Isolate? It also looks like libuv’s uv_queue_work() might be able to solve this, but since I don’t start the thread, I can’t see how you would use it.
When you declare
Persistent<Function> fnin your code,fnis a stack-allocated variable.fnis aPersistent<Function>, which is a handle class, and it will contain a pointer to some heap-allocated value of typeFunction, butfnitself is on the stack.This means that when you call
registerListener(&callback, &fn),&fnis taking the address of the handle (typePersistent<Function>), not the address of theFunctionon the heap. When your function exits, the handle will be destroyed but theFunctionitself will remain on the heap.So as a fix, I suggest passing the address of the
Functioninstead of the address of the handle, like this:(note that
operator*on aPersistent<T>returns aT*rather than the more conventionalT&, c.f. http://bespin.cz/~ondras/html/classv8_1_1Handle.html)You’ll also have to adjust
callbackto account for the fact thatcontextis now a raw pointer to aFunction, like this:Creating a
Persistent<Function>from a raw Function pointer here is OK because we know thatcontextis actually a persistent object.I’ve also changed
(*func)->Call(...)tofunc->Call(...)for brevity; they do the same thing for V8 handles.