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

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 ?

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:
read your code carefully (obvious)
executing member function on nullptr actualy works if there isn't any member access in the function (maybe it's obvious for an experienced cpp dev)
Native Addons live in their own vm, static fields aren't shared between vms.

Related

Crashes after parsing the equation

The application want to parse a string equation to mathematics and return the data to user. for this purpose the library is used is exprtk
for easy analysis I have shared minimum working code
minimum working code
when application parses the string to code back to back [multithreaded but locked]
void reset()
{
// Why? because msvc doesn't support swap properly.
//stack_ = std::stack<std::pair<char,std::size_t> >();
/**
it was crashing on destructor on ~deque()
stating memory reallocation
so I change it to pop so for now this has been resolved
*/
while(stack_.size()) stack_.pop();
state_ = true;
error_token_.clear();
}
now the code always crashes on
static inline void destroy(control_block*& cntrl_blck)
{
if (cntrl_blck)
{
/**now crashes on this condition check*/
if ( (0 != cntrl_blck->ref_count) && (0 == --cntrl_blck->ref_count) )
{
delete cntrl_blck;
}
cntrl_blck = 0;
}
}
UPDATE
pastebin code updated new code with main has been added with main and minimum working code.
all the shared_ptr has been removed. now they are normal objects.
as for exprtk reset function has been changed to original one
void reset()
{
// Why? because msvc doesn't support swap properly.
stack_ = std::stack<std::pair<char,std::size_t> >();
state_ = true;
error_token_.clear();
}
and backtrace of gdb has been added backtrace

assign std::unique_ptr to std::function

There is a custom defined map, with an element std::function()>.
The lambda code is working, but I don't know how to expand it to a normal formation. The code is following.
class TestA{
public:
TestA() {}
~TestA() {}
TestA(const TestA &) {}
static void print()
{
cout << __FUNCTION__ << endl;
return;
}
};
void testComplexMap1()
{
typedef map<string, std::function<std::unique_ptr<TestA>()>> TempMap;
TempMap m;
// the lambda format code, it works
//m.insert({ "TestA", []() {return std::unique_ptr<TestA>(new TestA());}});
// I want to expand it, but failed.
TestA *t = new TestA();
//function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t));
function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)()); //warning here
//m.emplace("TestA", fp); // compile error here
}
Any help will be greatly appreciated.
fp is not initialized with a function so compilation fails.
You can expand it like this:
TestA *t = new TestA();
std::unique_ptr<TestA> UT(t);
auto func = [&]() { return move(UT);};
std::function<std::unique_ptr<TestA>()> fp(func);
m.emplace("TestA", fp);
See DEMO.
In C++ everything that looks like it could be a declaration is treated as such.
This means the line
function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)());
is interpreted as:
fp is the declaration of a function returning an std::function<unique_ptr<TestA>()> and expecting a parameter called t which is a function pointer to a function returning a std::unique_ptr<TestA> and getting no parameter. (Which is not what you intended.)
This also means that the t in this line is not the same t as in the previous line.
You have to pass fp something that is actually callable like this:
std::unique_ptr<TestA> f() {
return std::make_unique<TestA>();
}
void testComplexMap1() {
// ...
function<unique_ptr<TestA>()> fp(f);
m.emplace("TestA1", fp);
}
If you want to add a function to the map that wraps an existing pointer into a unique_ptr you would need either a functor:
class Functor {
public:
Functor(TestA * a) : m_a(a) {}
~Functor() { delete m_a; }
std::unique_ptr<TestA> operator()(){
auto x = std::unique_ptr<TestA>(m_a);
m_a = nullptr;
return std::move(x);
}
private:
TestA * m_a;
};
void testComplexMap1() {
//...
TestA * t = new TestA();
m.emplace("TestA", Functor(t));
}
Or a lambda with capture:
void testComplexMap1() {
//...
TestA * t = new TestA();
m.emplace("TestA", [t](){ return std::unique_ptr<TestA>(t); });
}
The lamda is translated more or less to something like the Functor class. However in each case you have to be really careful: The functions in the map that encapsulate an existing pointer into a std::unique_ptr can and should only be called once.
If you don't call them, memory allocated for t won't be freed. If you call them more than once you get either a std::unique_ptr to nullptr (in my Functor class variant) or a more than one std::unique_ptr tries to manage the same memory region (in the lambda with capture variant), which will crash as soon as the second std::unique_ptr is deleted.
In short: I would advice against writing code like this and only put functions in the map that are callable multiple times.

Iterative MenuLayer Pebble

I am trying to create an app on pebble using MenuLayer. My intention is to create Menu's and then sub-menus using the MenuLayer.
I did some basic implementation using "menu_layer_set_callbacks" method and registering callbacks methods for each submenu layers. However, now I realise its getting too messy.
I want to know if there is any easy way out provided in the framework to meet this requirement.
Thanks.
KK
I don't know what you ended up with, but for my project, I made a set of sub-windows but reuses the same callbacks, you can pass custom data to let each know what type it is. Then just push the required sub-windows as needed
void sub_window_load(Window* parentWindow) {
Layer* window_layer = window_get_root_layer(parentWindow);
const GRect bounds = layer_get_frame(window_layer);
MenuLayer* new_layer = menu_layer_create(bounds);
const int context = *((int*) window_get_user_data(parentWindow));
if (context == ID_A) s_A_layer = new_layer;
else if (context == ID_B) s_B_layer = new_layer;
menu_layer_set_callbacks(new_layer, window_get_user_data(parentWindow), (MenuLayerCallbacks){
.get_num_sections = sub_menu_get_num_sections_callback,
.get_num_rows = sub_menu_get_num_rows_callback
/* etc */
});
menu_layer_set_click_config_onto_window(new_layer, parentWindow);
layer_add_child(window_layer, menu_layer_get_layer(new_layer));
}
void createSubWin(Window** w, int* context) {
*w = window_create();
window_set_user_data(*w, context);
window_set_window_handlers(*w, (WindowHandlers) {
.load = sub_window_load,
.unload = sub_window_unload
});
}

Monitor and ReaderWriterLockSlim aren't working

I tried to implement a typical threading application where one thread asks a device is data is available, copies the data to its own memory and sends an event to the main thread that the data is available. The main thread copies the data to its own memory and displays it on the GUI.
For this I used Visual Studio 2012 and C++/CLI with Winforms.
There is a class “Work” which holds the thread method “checkDataIsAvailable”. The “Work” class implements an interface (rather an abstract class) with a delegate “OnRetrievedData” which works as event and calls “BeginInvoke” in “Form1” to have an asynchronous behavior. And there is a method “getData” where the main thread can get the data from the “checkDataIsAvailable” thread. Furthermore the “Work” class tries to get the data from the class “ValueGenerator” which could represents any real device. I identifies a critical section for the “data” in the “Work” class called “array^ m_Data;”. The problem is that neither the “Monitor” nor the “ReaderWriterLockSlim” work approach is working.
With “Monitor” the GUI has a delayed responding and many updates are missing.
With “ReaderWriterLockSlim” the application crashes.
And without saving the critical section the application works. But I don’t know the reason because I’m sure that the data must be saved.
I would like to simplify the source code and emphasize the important things.
Most important is the thread method:
System::Void Work::checkDataIsAvailable()
{
while ( ( Thread::CurrentThread->ThreadState & Threading::ThreadState::Running) == Threading::ThreadState::Running )
{
m_WaitForDoCheckDataIsAvailableHandle->WaitOne();
//Monitor::Enter(m_LockData);
m_rwlock->EnterWriteLock();
m_Data = m_ValueGenerator->getData();
m_rwlock->ExitWriteLock();
//Monitor::Exit(m_LockData);
if ( nullptr != OnRetrievedData)
{
OnRetrievedData();
}
}
}
Here you see the copy process from the "ValueGenerator" to the variable m_Data. In my eyes this is a critical section. Then the event "OnRetrievedData" will be send that the data is available.
This event will get the Form1:
System::Void Form1::OnAcquisitionUpdate()
{
if(this->InvokeRequired == true)
{
OnAcquisitionUpdateDelegate^ onAcquisitionUpdateDelegate = gcnew OnAcquisitionUpdateDelegate(this, &Form1::OnAcquisitionUpdate);
this->BeginInvoke(onAcquisitionUpdateDelegate);
//this->Invoke(onAcquisitionUpdateDelegate);
}
else
{
if ( nullptr != m_Work )
{
//Thread::Sleep(5000);
array<System::Int32>^ data;
m_Work->getData(data);
dataResult_label->Text = data->Length.ToString();
}
}
}
"Form1::OnAcquisitionUpdate" changes it to the main thread via "BeginInvoke" and calls again the "Form1::OnAcquisitionUpdate" but now "InvokeRequired" is false so the "Work" class be called to get the data from the main thread.
System::Void Work::getData(array<System::Int32>^% data)
{
//Monitor::Enter(m_LockData);
m_rwlock->EnterReadLock();
Console::WriteLine(" getData() -> Data length = {0}", m_Data->Length);
data = m_Data;
m_rwlock->EnterReadLock();
//Monitor::Exit(m_LockData);
}
Here I see the next critical section where the data will be copied for the caller Form1.
It would be nice if anybody could help in this case.
I found a solution with a bool flag. Th flag is called "System::Boolean m_bCanWriteData;" and will be used in "Work::checkDataIsAvailable()" and "Work::getData(...)" in this way.
System::Void Work::checkDataIsAvailable()
{
while ( ( Thread::CurrentThread->ThreadState & Threading::ThreadState::Running) == Threading::ThreadState::Running )
{
m_WaitForDoCheckDataIsAvailableHandle->WaitOne();
#ifdef Use_Monitor
Monitor::Enter(m_LockData);
#endif
#ifdef Use_RW_Lock
m_rwlock->EnterWriteLock();
#endif
if ( m_bCanWriteData )
{
m_bCanWriteData = false;
m_Data = m_ValueGenerator->getData();
debugOutput("Work::checkDataIsAvailable() -> Data length = " + m_Data->Length);
if ( nullptr != OnRetrievedData)
{
OnRetrievedData();
}
}
#ifdef Use_RW_Lock
m_rwlock->ExitWriteLock();
#endif
#ifdef Use_Monitor
Monitor::Exit(m_LockData);
#endif
}
}
System::Void Work::getData(array<System::Int32>^% data)
{
debugOutput("Work::getData() START");
#ifdef Use_Monitor
Monitor::Enter(m_LockData);
debugOutput("Work::getData() + Monitor::Enter");
#endif
#ifdef Use_RW_Lock
m_rwlock->EnterReadLock();
#endif
m_WaitForDoCheckDataIsAvailableHandle->Reset(); // Block the thread method.
debugOutput("Work::getData() -> Data length = " + m_Data->Length);
data = m_Data;
m_bCanWriteData = true;
if ( m_bIsRunning )
{
m_WaitForDoCheckDataIsAvailableHandle->Set(); // Start the thread method.
}
#ifdef Use_RW_Lock
m_rwlock->EnterReadLock();
#endif
#ifdef Use_Monitor
Monitor::Exit(m_LockData);
#endif
debugOutput("Work::getData() END");
}
As you see the writting into and reading out is controlled and it works for the Monitor.

Safari plugin crashes on NPN_GetValue

My plugin code crashes when I call the NPN_GetValue. Basically I created a scriptable object which has a 'getDevice' method that can return a device array to JavaScript. Below is the code snippet.
static bool mainNPObjectInvoke(NPObject *obj, NPIdentifier identifier, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
printf("create main object");
MainNPObject *mainObject = (MainNPObject *)obj;
if (identifier == methodIdentifiers[METHOD_ID_GET_DEVICES])
{
NPObject *windowObj = NULL;
browser->getvalue(mainObject->npp, NPNVWindowNPObject, &windowObj);
// it crashed here
....
}
}
I created the MainNPObject instance with below method.
NPObject *createMainNPObject(NPP npp)
{
MainNPObject *object = (MainNPObject *)browser->createobject(npp, &mainNPClass);
object->npp = npp;
theMainObject = object;
return (NPObject *)object;
}
The createMainNPObject is called in the plugin function I provided to browser.
NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
{
PluginObject *obj = instance->pdata;
switch (variable) {
case NPPVpluginCoreAnimationLayer:
if (!obj->rootLayer)
setupLayerHierarchy(obj);
*(CALayer **)value = obj->rootLayer;
return NPERR_NO_ERROR;
case NPPVpluginScriptableNPObject:
if (!obj->mainObject)
{
obj->mainObject = createMainNPObject(instance);
}
....
}
And the allocate function is as below.
static NPObject *mainNPObjectAllocate(NPP npp, NPClass *class)
{
initializeIdentifiers();
MainNPObject *mainObject = malloc(sizeof(MainNPObject));
mainObject->deviceManager = [[DeviceManager alloc] init];
return (NPObject *)mainObject;
}
Definition of MainNPObject:
typedef struct
{
NPObject *npobject;
NPP npp;
DeviceManager *deviceManager;
} MainNPObject;
By debugging the code, I found that the system raised an EXC_BAD_ACCESS when calling the browser->getValue and it looks like the npp pointer is invalid.
0x00007fff83f82dab <+0019> je 0x7fff83f82db9 <_ZN6WebKit14NetscapePlugin7fromNPPEP4_NPP+33>
0x00007fff83f82dad <+0021> incl 0x8(%rax)
Can someone help me out?
Thanks!
Hmm; not seeing anything obvious. Try adding another parameter (an int?) to your structure and set it during allocate or immediately afterwords, then later on check to see if it's still the value you set before you call getvalue. See if your struct is somehow getting corrupt. That happened to me once when I was casting the NPObject funny in a non-obvious way.

Resources