c++11node.js-addonnode.js-nan

nodejs native addon : how to modify the value of c++ object's member contained in another native addon


First some context, i got two nodejs native addon. The first one contains a static c++ object "Conn" exposed using an v8 object internal field as described in the embedder's guide

NAN_METHOD(cobject) {
    auto isolate = Isolate::GetCurrent();
    Conn* p = &ConnHolder::connection;
    Local<ObjectTemplate> conn_templ = ObjectTemplate::New(isolate);
    conn_templ->SetInternalFieldCount(1); 
    Local<Object> obj = conn_templ->NewInstance();
    obj->SetInternalField(0, External::New(isolate, p));
    info.GetReturnValue().Set(obj);
}

In my other native addon, i'm loading the first one using c++ code and i expose a function called test containing two calls on the Conn object "callToDummyFunction()" and "callToFunctionWithMemberAccess()"

// persistent handle for the main addon
static Persistent<Object> node_main;


void Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // get `require` function
    Local<Function> require = module->Get(String::NewFromUtf8(isolate, "require")).As<Function>();
    Local<Value> args[] = { String::NewFromUtf8(isolate, "path_to_my_addon\\addon.node") };

    Local<Object> main = require->Call(module, 1, args).As<Object>();
    node_main.Reset(isolate, main); 
    NAN_EXPORT(exports, test);

}

NAN_METHOD(test) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // get local handle from persistent
    Local<Object> main = Local<Object>::New(isolate, node_main);

    // get `cobject` function to get pointer from internal field
    Local<Function> createdMain = main->Get(String::NewFromUtf8(isolate,     "cobject")).As<Function>();

    Local<Object> callResult = createdMain->Call(main, 0, nullptr).As<Object>();
    Local<Object> self = info.Holder();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();

    // from there i get a pointer to my Conn object
    Conn* con = static_cast<Conn*>(ptr);

    conn->callToDummyFunction();
    conn->callToFunctionWithMemberAccess();

    info.GetReturnValue().Set(10);

}

Then i'm launching a nodejs session using "node", i load the first and second addon using two require calls and finally i'm calling the method test on the second addon.

The method test is executed, the call to "callToDummyFunction" is executed successfully but the call to "callToFunctionWithMemberAccess" crash and also kill the node session.

Ok, so what is the difference between "callToDummyFunction" and "callToFunctionWithMemberAccess" ?

bool Conn::callToDummyFunction()
{
    cout << "callToDummyFunction" << endl;
    return true;
}

bool Conn::callToFunctionWithMemberAccess()
{
    cout << "callToFunctionWithMemberAccess " << someIntMember << endl;
    return true;
}

So, it seems accessing a member of the Conn object generate an error and crash the node session. The node session does not output any message before crashing.

Can someone tell me why?

And/Or

How to get an error message ?


Solution

  • I'm answering my own question. In fact, i'm stupid but at least my stupidity made me learn some strange cpp things.

    So, first of all the stupid answer. Instead of using my returned object i'm using a totaly unrelated object :(

    Local<Object> callResult = createdMain->Call(main, 0, nullptr).As<Object>();
    Local<Object> self = info.Holder();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    

    Why using

    Local self = info.Holder();

    instead of callResult. The right code would be

    Local<Object> callResult = createdMain->Call(main, 0, nullptr).As<Object>();
    Local<External> wrap = Local<External>::Cast(callResult->GetInternalField(0));
    

    What did i learn from this stupid mistake: