In <napi.h>
, there are some overloads declaration for the static method Accessor
in the class PropertyDescriptor
.
One of such overloads declaration is here:
template <typename Getter>
static PropertyDescriptor Accessor(Napi::Env env,
Napi::Object object,
const std::string& utf8name,
Getter getter,
napi_property_attributes attributes = napi_default,
void* data = nullptr);
That declaration wants a reference to a const std::string
The definition of that declaration is in <napi-inl.h>:
template <typename Getter>
inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
Napi::Object object,
const std::string& utf8name,
Getter getter,
napi_property_attributes attributes,
void* data) {
return Accessor(env, object, utf8name.c_str(), getter, attributes, data);
}
As you can see, the implementation takes the .c_str()
of the passed std::string
, as the implementation in fact uses another overload which wants a const char*
.
The overload used is also in <napi-inl.h>
:
template <typename Getter>
inline PropertyDescriptor
PropertyDescriptor::Accessor(Napi::Env env,
Napi::Object object,
const char* utf8name,
Getter getter,
napi_property_attributes attributes,
void* data) {
using CbData = details::CallbackData<Getter, Napi::Value>;
auto callbackData = new CbData({ getter, data });
napi_status status = AttachData(env, object, callbackData);
if (status != napi_ok) {
delete callbackData;
NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
}
return PropertyDescriptor({
utf8name,
nullptr,
nullptr,
CbData::Wrapper,
nullptr,
nullptr,
attributes,
callbackData
});
}
That implementation uses Node-API, as node-addon-api
is just a C++ wrapper arround Node-API. The fact is that the const char* utf8name
obtained from .c_str()
is passed as is to the constructor and is stored in the private member napi_property_descriptor _desc;
Conclusion: each time you use Napi::PropertyDescriptor::Accessor
passing a std::string and then storing the PD in a vector, or just making the string goes out of scope with the PD still here, you trigger an undefined behavior!
Example:
Napi::Object TheNewObject = Napi::Object::New(env);
std::vector<Napi::PropertyDescriptor> vProps;
for (size_t index = 0; index < 2; ++index ) {
std::string strName("MyName_");
strName += std::to_string(index);
auto PD = Napi::PropertyDescriptor::Accessor(env, TheNewObject, strName, Caller);
vProps.push_back(PD);
}
I opened an issue here, 12 days ago, with no avail.
EDIT: After reading comments, I should add that:
napi_property_descriptor
is a simple C structure.napi_define_properties
There is indeed a problem with current implementations of PropertyDescriptor
.
See https://github.com/nodejs/node-addon-api/issues/1127#issuecomment-1036394322
Glad I wasn't completely delirious.