You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Reference count of ObjectWrap changed in Node.js 14.17.0 #998
Not sure if this is an issue of napi or node-addon-api, but we found this when using node-addon-api so I post it here.
The code below:
#include<napi.h>classMyObject : publicNapi::ObjectWrap<MyObject> {
public:static Napi::Object Init(Napi::Env env, Napi::Object exports);
MyObject(const Napi::CallbackInfo& info);
~MyObject();
};
Napi::Object MyObject::Init(Napi::Env env, Napi::Object exports) {
Napi::Function func =
DefineClass(env,
"MyObject",
{});
Napi::FunctionReference* constructor = newNapi::FunctionReference();
*constructor = Napi::Persistent(func);
env.SetInstanceData(constructor);
exports.Set("MyObject", func);
return exports;
}
MyObject::MyObject(const Napi::CallbackInfo& info)
: Napi::ObjectWrap<MyObject>(info) {
this->Ref(); // Nothing special except that we Ref() here to keep this object from been garbage collected while other resources still alive
}
MyObject::~MyObject() {
uint32_t count = -1;
count = this->Unref(); // And Unref() in destructor.fprintf(stderr, "count %d\n", count); // Log the count.
}
Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
returnMyObject::Init(env, exports);
}
NODE_API_MODULE(addon, InitAll)
varaddon=require('bindings')('addon');newaddon.MyObject(10);// Create an instance and wait the process to exit.
Running the code in Node.js 14.16 will get:
count 0
In Node.js 14.17, the result becomes:
count 1
Though the code snippet doesn't throw here, in our real programs, running similar codes in Node.js 14.17 causes:
When enable cpp exceptions i.e. NAPI_CPP_EXCEPTIONS, run the script will result in:
// Mac
libc++abi.dylib: terminating with uncaught exception of type Napi::Error
// Debian
terminate called after throwing an instance of 'Napi::Error'
what(): Unknown failure
Aborted (core dumped)
@oyyd can you share the core dump backtrace in your realm programs? (you can wipe out sensitive data from the text backtrace) It will be helpful to track down the problem since you said the code snippet doesn't crash.
Although I didn't build a debug version of Node.js to inspect the coredump file, the code that aborts inside UnixDgramSocket::UnrefAll() is this->Unref(); which was found by changing of the code.
Although this crash is introduced in a newer version of Node.js, the first impression came to me that this is a user code bug in terms of API semantics. Calling napi_reference_unref/Reference<T>::Unref in ObjectWraps destructor should be avoided as the destructor is trigger by garbage collection, which means the object's ref count is already 0. @gabrielschulhof maybe you can elaborate on the error returning behavior https://github.com/nodejs/node/blob/master/src/js_native_api_v8.cc#L2523-L2526? Anyway, it is meaningless when the ref count goes down to negative values.
@oyyd can you share the build configuration and Node.js version when not calling Unref in ObjectWrap subclass destructors? I cannot reproduce the problem either when c++ exceptions are enabled or not locally.
@oyyd sorry about the delay but your example did call Unref in the destructor. I comment out those lines Unref in MyObject::~MyObject and in Node.js v14.17.1 it run alright.
This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.
Activity
legendecas commentedon May 14, 2021
@oyyd can you share the core dump backtrace in your realm programs? (you can wipe out sensitive data from the text backtrace) It will be helpful to track down the problem since you said the code snippet doesn't crash.
oyyd commentedon May 14, 2021
@legendecas The backtrace is:
Although I didn't build a debug version of Node.js to inspect the coredump file, the code that aborts inside
UnixDgramSocket::UnrefAll()isthis->Unref();which was found by changing of the code.oyyd commentedon May 17, 2021
@legendecas I forgot to enable cpp exceptions. The code snippet also aborts when cpp exceptions enabled.
legendecas commentedon May 23, 2021
I believe it is this commit nodejs/node@03806a0#diff-4b35cbf831be523a4f3e5aac3729c95490ed220892695d0e4245c15c1f63cfc1R278 making the problem prominent.
Although this crash is introduced in a newer version of Node.js, the first impression came to me that this is a user code bug in terms of API semantics. Calling
napi_reference_unref/Reference<T>::UnrefinObjectWraps destructor should be avoided as the destructor is trigger by garbage collection, which means the object's ref count is already 0. @gabrielschulhof maybe you can elaborate on the error returning behavior https://github.com/nodejs/node/blob/master/src/js_native_api_v8.cc#L2523-L2526? Anyway, it is meaningless when the ref count goes down to negative values.The value
1returned in Node.js v14.7 and later is from the default value defined here https://github.com/nodejs/node-addon-api/blob/main/napi-inl.h#L2594. Maybe returning 0 on non-napi_okstatus is more reasonable?oyyd commentedon May 24, 2021
I call
Unref()in destructor (or finalize callbacks) or it will also result in aborting:get:
legendecas commentedon May 24, 2021
@oyyd can you share the build configuration and Node.js version when not calling
UnrefinObjectWrapsubclass destructors? I cannot reproduce the problem either when c++ exceptions are enabled or not locally.oyyd commentedon May 25, 2021
@legendecas Please see this example https://github.com/oyyd/addon_abort_example. Thanks for your patient investigation:)
legendecas commentedon Jun 16, 2021
@oyyd sorry about the delay but your example did call
Unrefin the destructor. I comment out those linesUnrefinMyObject::~MyObjectand in Node.js v14.17.1 it run alright.github-actions commentedon Sep 15, 2021
This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.
remove destructor unref as per nodejs/node-addon-api#998