Skip to content

Commit 46bbbf0

Browse files
author
Gabriel Schulhof
committed
src: add addon entry point symbol cache
Determine whether the dlopen() of a certain addon is the first load of said addon, or if the addon had previously been loaded. This is accomplished by storing the addon's entry point in a set. If, upon a subsequent load, after determining the addon's entry point, it is found to already be present in the cache, then the handle returned by the subsequent dlopen() is closed.
1 parent 81f06ba commit 46bbbf0

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

src/node.cc

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ static std::string trace_enabled_categories; // NOLINT(runtime/string)
194194
static std::string trace_file_pattern = // NOLINT(runtime/string)
195195
"node_trace.${rotation}.log";
196196
static bool abort_on_uncaught_exception = false;
197+
static std::set<void*> addon_entry_points;
197198

198199
// Bit flag used to track security reverts (see node_revert.h)
199200
unsigned int reverted = 0;
@@ -1258,6 +1259,22 @@ inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
12581259
reinterpret_cast<napi_addon_register_func>(dlib->GetSymbolAddress(name));
12591260
}
12601261

1262+
// Initialize the addon, and close the DLib if this is a second-or-later
1263+
// initialization call.
1264+
template <typename Initializer, typename EntryPoint>
1265+
inline void CallAddonInitializer(Local<Object> exports,
1266+
Local<Value> module,
1267+
Local<Context> context,
1268+
const Initializer& init,
1269+
EntryPoint entry_point,
1270+
DLib* dlib) {
1271+
init(exports, module, context);
1272+
void* generic_entry_point = reinterpret_cast<void*>(entry_point);
1273+
if (!(addon_entry_points.insert(generic_entry_point).second)) {
1274+
dlib->Close();
1275+
}
1276+
}
1277+
12611278
// DLOpen is process.dlopen(module, filename, flags).
12621279
// Used to load 'module.node' dynamically shared objects.
12631280
//
@@ -1313,9 +1330,16 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
13131330

13141331
if (mp == nullptr) {
13151332
if (auto callback = GetInitializerCallback(&dlib)) {
1316-
callback(exports, module, context);
1333+
CallAddonInitializer(exports, module, context, callback, callback, &dlib);
13171334
} else if (auto napi_callback = GetNapiInitializerCallback(&dlib)) {
1318-
napi_module_register_by_symbol(exports, module, context, napi_callback);
1335+
CallAddonInitializer(exports, module, context,
1336+
[napi_callback] (Local<Object> exports,
1337+
Local<Value> module,
1338+
Local<Context> context) {
1339+
napi_module_register_by_symbol(exports, module, context,
1340+
napi_callback);
1341+
},
1342+
napi_callback, &dlib);
13191343
} else {
13201344
dlib.Close();
13211345
env->ThrowError("Module did not self-register.");
@@ -1329,7 +1353,7 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
13291353
// version. We must only give up after having checked to see if it has an
13301354
// appropriate initializer callback.
13311355
if (auto callback = GetInitializerCallback(&dlib)) {
1332-
callback(exports, module, context);
1356+
CallAddonInitializer(exports, module, context, callback, callback, &dlib);
13331357
return;
13341358
}
13351359
char errmsg[1024];
@@ -1359,10 +1383,34 @@ static void DLOpen(const FunctionCallbackInfo<Value>& args) {
13591383
mp->nm_link = modlist_addon;
13601384
modlist_addon = mp;
13611385

1362-
if (mp->nm_context_register_func != nullptr) {
1363-
mp->nm_context_register_func(exports, module, context, mp->nm_priv);
1386+
// N-API addons all hide behind a single callback, so its address is not
1387+
// suitable for caching. Grab the actual init callback address instead.
1388+
if (mp->nm_version == -1) {
1389+
auto napi_callback = napi_module_get_entry_point(mp);
1390+
CallAddonInitializer(exports, module, context,
1391+
[napi_callback] (Local<Object> exports,
1392+
Local<Value> module,
1393+
Local<Context> context) {
1394+
napi_module_register_by_symbol(exports, module, context,
1395+
napi_callback);
1396+
},
1397+
napi_callback, &dlib);
1398+
} else if (mp->nm_context_register_func != nullptr) {
1399+
CallAddonInitializer(exports, module, context,
1400+
[mp] (Local<Object> exports,
1401+
Local<Value> module,
1402+
Local<Context> context) {
1403+
mp->nm_context_register_func(exports, module, context, mp->nm_priv);
1404+
},
1405+
mp->nm_context_register_func, &dlib);
13641406
} else if (mp->nm_register_func != nullptr) {
1365-
mp->nm_register_func(exports, module, mp->nm_priv);
1407+
CallAddonInitializer(exports, module, context,
1408+
[mp] (Local<Object> exports,
1409+
Local<Value> module,
1410+
Local<Context> context) {
1411+
mp->nm_register_func(exports, module, mp->nm_priv);
1412+
},
1413+
mp->nm_register_func, &dlib);
13661414
} else {
13671415
dlib.Close();
13681416
env->ThrowError("Module has no declared entry point.");

src/node_api.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,10 @@ void napi_module_register_cb(v8::Local<v8::Object> exports,
842842

843843
} // end of anonymous namespace
844844

845+
napi_addon_register_func napi_module_get_entry_point(node::node_module* mp) {
846+
return static_cast<napi_module*>(mp->nm_priv)->nm_register_func;
847+
}
848+
845849
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
846850
v8::Local<v8::Value> module,
847851
v8::Local<v8::Context> context,

src/node_internals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,8 @@ void GetGroups(const v8::FunctionCallbackInfo<v8::Value>& args);
964964

965965
} // namespace node
966966

967+
napi_addon_register_func napi_module_get_entry_point(node::node_module* mp);
968+
967969
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
968970
v8::Local<v8::Value> module,
969971
v8::Local<v8::Context> context,

0 commit comments

Comments
 (0)