• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "node_binding.h"
2 #include <atomic>
3 #include "env-inl.h"
4 #include "node_builtins.h"
5 #include "node_errors.h"
6 #include "node_external_reference.h"
7 #include "util.h"
8 
9 #include <string>
10 
11 #if HAVE_OPENSSL
12 #define NODE_BUILTIN_OPENSSL_BINDINGS(V) V(crypto) V(tls_wrap)
13 #else
14 #define NODE_BUILTIN_OPENSSL_BINDINGS(V)
15 #endif
16 
17 #if NODE_HAVE_I18N_SUPPORT
18 #define NODE_BUILTIN_ICU_BINDINGS(V) V(icu)
19 #else
20 #define NODE_BUILTIN_ICU_BINDINGS(V)
21 #endif
22 
23 #if HAVE_INSPECTOR
24 #define NODE_BUILTIN_PROFILER_BINDINGS(V) V(profiler)
25 #else
26 #define NODE_BUILTIN_PROFILER_BINDINGS(V)
27 #endif
28 
29 #if HAVE_DTRACE || HAVE_ETW
30 #define NODE_BUILTIN_DTRACE_BINDINGS(V) V(dtrace)
31 #else
32 #define NODE_BUILTIN_DTRACE_BINDINGS(V)
33 #endif
34 
35 // A list of built-in bindings. In order to do binding registration
36 // in node::Init(), need to add built-in bindings in the following list.
37 // Then in binding::RegisterBuiltinBindings(), it calls bindings' registration
38 // function. This helps the built-in bindings are loaded properly when
39 // node is built as static library. No need to depend on the
40 // __attribute__((constructor)) like mechanism in GCC.
41 #define NODE_BUILTIN_STANDARD_BINDINGS(V)                                      \
42   V(async_wrap)                                                                \
43   V(blob)                                                                      \
44   V(block_list)                                                                \
45   V(buffer)                                                                    \
46   V(builtins)                                                                  \
47   V(cares_wrap)                                                                \
48   V(config)                                                                    \
49   V(contextify)                                                                \
50   V(credentials)                                                               \
51   V(errors)                                                                    \
52   V(fs)                                                                        \
53   V(fs_dir)                                                                    \
54   V(fs_event_wrap)                                                             \
55   V(heap_utils)                                                                \
56   V(http2)                                                                     \
57   V(http_parser)                                                               \
58   V(inspector)                                                                 \
59   V(js_stream)                                                                 \
60   V(js_udp_wrap)                                                               \
61   V(messaging)                                                                 \
62   V(module_wrap)                                                               \
63   V(mksnapshot)                                                                \
64   V(options)                                                                   \
65   V(os)                                                                        \
66   V(performance)                                                               \
67   V(pipe_wrap)                                                                 \
68   V(process_wrap)                                                              \
69   V(process_methods)                                                           \
70   V(report)                                                                    \
71   V(sea)                                                                       \
72   V(serdes)                                                                    \
73   V(signal_wrap)                                                               \
74   V(spawn_sync)                                                                \
75   V(stream_pipe)                                                               \
76   V(stream_wrap)                                                               \
77   V(string_decoder)                                                            \
78   V(symbols)                                                                   \
79   V(task_queue)                                                                \
80   V(tcp_wrap)                                                                  \
81   V(timers)                                                                    \
82   V(trace_events)                                                              \
83   V(tty_wrap)                                                                  \
84   V(types)                                                                     \
85   V(udp_wrap)                                                                  \
86   V(url)                                                                       \
87   V(util)                                                                      \
88   V(uv)                                                                        \
89   V(v8)                                                                        \
90   V(wasi)                                                                      \
91   V(wasm_web_api)                                                              \
92   V(watchdog)                                                                  \
93   V(worker)                                                                    \
94   V(zlib)
95 
96 #define NODE_BUILTIN_BINDINGS(V)                                               \
97   NODE_BUILTIN_STANDARD_BINDINGS(V)                                            \
98   NODE_BUILTIN_OPENSSL_BINDINGS(V)                                             \
99   NODE_BUILTIN_ICU_BINDINGS(V)                                                 \
100   NODE_BUILTIN_PROFILER_BINDINGS(V)                                            \
101   NODE_BUILTIN_DTRACE_BINDINGS(V)
102 
103 // This is used to load built-in bindings. Instead of using
104 // __attribute__((constructor)), we call the _register_<modname>
105 // function for each built-in bindings explicitly in
106 // binding::RegisterBuiltinBindings(). This is only forward declaration.
107 // The definitions are in each binding's implementation when calling
108 // the NODE_BINDING_CONTEXT_AWARE_INTERNAL.
109 #define V(modname) void _register_##modname();
110 NODE_BUILTIN_BINDINGS(V)
111 #undef V
112 
113 #ifdef _AIX
114 // On AIX, dlopen() behaves differently from other operating systems, in that
115 // it returns unique values from each call, rather than identical values, when
116 // loading the same handle.
117 // We try to work around that by providing wrappers for the dlopen() family of
118 // functions, and using st_dev and st_ino for the file that is to be loaded
119 // as keys for a cache.
120 
121 namespace node {
122 namespace dlwrapper {
123 
124 struct dl_wrap {
125   uint64_t st_dev;
126   uint64_t st_ino;
127   uint64_t refcount;
128   void* real_handle;
129 
130   struct hash {
operator ()node::dlwrapper::dl_wrap::hash131     size_t operator()(const dl_wrap* wrap) const {
132       return std::hash<uint64_t>()(wrap->st_dev) ^
133              std::hash<uint64_t>()(wrap->st_ino);
134     }
135   };
136 
137   struct equal {
operator ()node::dlwrapper::dl_wrap::equal138     bool operator()(const dl_wrap* a,
139                     const dl_wrap* b) const {
140       return a->st_dev == b->st_dev && a->st_ino == b->st_ino;
141     }
142   };
143 };
144 
145 static Mutex dlhandles_mutex;
146 static std::unordered_set<dl_wrap*, dl_wrap::hash, dl_wrap::equal>
147     dlhandles;
148 static thread_local std::string dlerror_storage;
149 
wrapped_dlerror()150 char* wrapped_dlerror() {
151   return &dlerror_storage[0];
152 }
153 
wrapped_dlopen(const char * filename,int flags)154 void* wrapped_dlopen(const char* filename, int flags) {
155   CHECK_NOT_NULL(filename);  // This deviates from the 'real' dlopen().
156   Mutex::ScopedLock lock(dlhandles_mutex);
157 
158   uv_fs_t req;
159   auto cleanup = OnScopeLeave([&]() { uv_fs_req_cleanup(&req); });
160   int rc = uv_fs_stat(nullptr, &req, filename, nullptr);
161 
162   if (rc != 0) {
163     dlerror_storage = uv_strerror(rc);
164     return nullptr;
165   }
166 
167   dl_wrap search = {
168     req.statbuf.st_dev,
169     req.statbuf.st_ino,
170     0, nullptr
171   };
172 
173   auto it = dlhandles.find(&search);
174   if (it != dlhandles.end()) {
175     (*it)->refcount++;
176     return *it;
177   }
178 
179   void* real_handle = dlopen(filename, flags);
180   if (real_handle == nullptr) {
181     dlerror_storage = dlerror();
182     return nullptr;
183   }
184   dl_wrap* wrap = new dl_wrap();
185   wrap->st_dev = req.statbuf.st_dev;
186   wrap->st_ino = req.statbuf.st_ino;
187   wrap->refcount = 1;
188   wrap->real_handle = real_handle;
189   dlhandles.insert(wrap);
190   return wrap;
191 }
192 
wrapped_dlclose(void * handle)193 int wrapped_dlclose(void* handle) {
194   Mutex::ScopedLock lock(dlhandles_mutex);
195   dl_wrap* wrap = static_cast<dl_wrap*>(handle);
196   int ret = 0;
197   CHECK_GE(wrap->refcount, 1);
198   if (--wrap->refcount == 0) {
199     ret = dlclose(wrap->real_handle);
200     if (ret != 0) dlerror_storage = dlerror();
201     dlhandles.erase(wrap);
202     delete wrap;
203   }
204   return ret;
205 }
206 
wrapped_dlsym(void * handle,const char * symbol)207 void* wrapped_dlsym(void* handle, const char* symbol) {
208   if (handle == RTLD_DEFAULT || handle == RTLD_NEXT)
209     return dlsym(handle, symbol);
210   dl_wrap* wrap = static_cast<dl_wrap*>(handle);
211   return dlsym(wrap->real_handle, symbol);
212 }
213 
214 #define dlopen node::dlwrapper::wrapped_dlopen
215 #define dlerror node::dlwrapper::wrapped_dlerror
216 #define dlclose node::dlwrapper::wrapped_dlclose
217 #define dlsym node::dlwrapper::wrapped_dlsym
218 
219 }  // namespace dlwrapper
220 }  // namespace node
221 
222 #endif  // _AIX
223 
224 #ifdef __linux__
libc_may_be_musl()225 static bool libc_may_be_musl() {
226   static std::atomic_bool retval;  // Cache the return value.
227   static std::atomic_bool has_cached_retval { false };
228   if (has_cached_retval) return retval;
229   retval = dlsym(RTLD_DEFAULT, "gnu_get_libc_version") == nullptr;
230   has_cached_retval = true;
231   return retval;
232 }
233 #elif defined(__POSIX__)
libc_may_be_musl()234 static bool libc_may_be_musl() { return false; }
235 #endif  // __linux__
236 
237 namespace node {
238 
239 using v8::Context;
240 using v8::Exception;
241 using v8::Function;
242 using v8::FunctionCallbackInfo;
243 using v8::Local;
244 using v8::Object;
245 using v8::String;
246 using v8::Value;
247 
248 // Globals per process
249 static node_module* modlist_internal;
250 static node_module* modlist_linked;
251 static thread_local node_module* thread_local_modpending;
252 
253 // This is set by node::Init() which is used by embedders
254 bool node_is_initialized = false;
255 
node_module_register(void * m)256 extern "C" void node_module_register(void* m) {
257   struct node_module* mp = reinterpret_cast<struct node_module*>(m);
258 
259   if (mp->nm_flags & NM_F_INTERNAL) {
260     mp->nm_link = modlist_internal;
261     modlist_internal = mp;
262   } else if (!node_is_initialized) {
263     // "Linked" modules are included as part of the node project.
264     // Like builtins they are registered *before* node::Init runs.
265     mp->nm_flags = NM_F_LINKED;
266     mp->nm_link = modlist_linked;
267     modlist_linked = mp;
268   } else {
269     thread_local_modpending = mp;
270   }
271 }
272 
273 namespace binding {
274 
275 static struct global_handle_map_t {
276  public:
setnode::binding::global_handle_map_t277   void set(void* handle, node_module* mod) {
278     CHECK_NE(handle, nullptr);
279     Mutex::ScopedLock lock(mutex_);
280 
281     map_[handle].module = mod;
282     // We need to store this flag internally to avoid a chicken-and-egg problem
283     // during cleanup. By the time we actually use the flag's value,
284     // the shared object has been unloaded, and its memory would be gone,
285     // making it impossible to access fields of `mod` --
286     // unless `mod` *is* dynamically allocated, but we cannot know that
287     // without checking the flag.
288     map_[handle].wants_delete_module = mod->nm_flags & NM_F_DELETEME;
289     map_[handle].refcount++;
290   }
291 
get_and_increase_refcountnode::binding::global_handle_map_t292   node_module* get_and_increase_refcount(void* handle) {
293     CHECK_NE(handle, nullptr);
294     Mutex::ScopedLock lock(mutex_);
295 
296     auto it = map_.find(handle);
297     if (it == map_.end()) return nullptr;
298     it->second.refcount++;
299     return it->second.module;
300   }
301 
erasenode::binding::global_handle_map_t302   void erase(void* handle) {
303     CHECK_NE(handle, nullptr);
304     Mutex::ScopedLock lock(mutex_);
305 
306     auto it = map_.find(handle);
307     if (it == map_.end()) return;
308     CHECK_GE(it->second.refcount, 1);
309     if (--it->second.refcount == 0) {
310       if (it->second.wants_delete_module)
311         delete it->second.module;
312       map_.erase(handle);
313     }
314   }
315 
316  private:
317   Mutex mutex_;
318   struct Entry {
319     unsigned int refcount;
320     bool wants_delete_module;
321     node_module* module;
322   };
323   std::unordered_map<void*, Entry> map_;
324 } global_handle_map;
325 
DLib(const char * filename,int flags)326 DLib::DLib(const char* filename, int flags)
327     : filename_(filename), flags_(flags), handle_(nullptr) {}
328 
329 #ifdef __POSIX__
Open()330 bool DLib::Open() {
331   handle_ = dlopen(filename_.c_str(), flags_);
332   if (handle_ != nullptr) return true;
333   errmsg_ = dlerror();
334   return false;
335 }
336 
Close()337 void DLib::Close() {
338   if (handle_ == nullptr) return;
339 
340   if (libc_may_be_musl()) {
341     // musl libc implements dlclose() as a no-op which returns 0.
342     // As a consequence, trying to re-load a previously closed addon at a later
343     // point will not call its static constructors, which Node.js uses.
344     // Therefore, when we may be using musl libc, we assume that the shared
345     // object exists indefinitely and keep it in our handle map.
346     return;
347   }
348 
349   int err = dlclose(handle_);
350   if (err == 0) {
351     if (has_entry_in_global_handle_map_)
352       global_handle_map.erase(handle_);
353   }
354   handle_ = nullptr;
355 }
356 
GetSymbolAddress(const char * name)357 void* DLib::GetSymbolAddress(const char* name) {
358   return dlsym(handle_, name);
359 }
360 #else   // !__POSIX__
Open()361 bool DLib::Open() {
362   int ret = uv_dlopen(filename_.c_str(), &lib_);
363   if (ret == 0) {
364     handle_ = static_cast<void*>(lib_.handle);
365     return true;
366   }
367   errmsg_ = uv_dlerror(&lib_);
368   uv_dlclose(&lib_);
369   return false;
370 }
371 
Close()372 void DLib::Close() {
373   if (handle_ == nullptr) return;
374   if (has_entry_in_global_handle_map_)
375     global_handle_map.erase(handle_);
376   uv_dlclose(&lib_);
377   handle_ = nullptr;
378 }
379 
GetSymbolAddress(const char * name)380 void* DLib::GetSymbolAddress(const char* name) {
381   void* address;
382   if (0 == uv_dlsym(&lib_, name, &address)) return address;
383   return nullptr;
384 }
385 #endif  // !__POSIX__
386 
SaveInGlobalHandleMap(node_module * mp)387 void DLib::SaveInGlobalHandleMap(node_module* mp) {
388   has_entry_in_global_handle_map_ = true;
389   global_handle_map.set(handle_, mp);
390 }
391 
GetSavedModuleFromGlobalHandleMap()392 node_module* DLib::GetSavedModuleFromGlobalHandleMap() {
393   has_entry_in_global_handle_map_ = true;
394   return global_handle_map.get_and_increase_refcount(handle_);
395 }
396 
397 using InitializerCallback = void (*)(Local<Object> exports,
398                                      Local<Value> module,
399                                      Local<Context> context);
400 
GetInitializerCallback(DLib * dlib)401 inline InitializerCallback GetInitializerCallback(DLib* dlib) {
402   const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
403   return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
404 }
405 
GetNapiInitializerCallback(DLib * dlib)406 inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
407   const char* name =
408       STRINGIFY(NAPI_MODULE_INITIALIZER_BASE) STRINGIFY(NAPI_MODULE_VERSION);
409   return reinterpret_cast<napi_addon_register_func>(
410       dlib->GetSymbolAddress(name));
411 }
412 
GetNapiAddonGetApiVersionCallback(DLib * dlib)413 inline node_api_addon_get_api_version_func GetNapiAddonGetApiVersionCallback(
414     DLib* dlib) {
415   return reinterpret_cast<node_api_addon_get_api_version_func>(
416       dlib->GetSymbolAddress(STRINGIFY(NODE_API_MODULE_GET_API_VERSION)));
417 }
418 
419 // DLOpen is process.dlopen(module, filename, flags).
420 // Used to load 'module.node' dynamically shared objects.
421 //
422 // FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
423 // when two contexts try to load the same shared object. Maybe have a shadow
424 // cache that's a plain C list or hash table that's shared across contexts?
DLOpen(const FunctionCallbackInfo<Value> & args)425 void DLOpen(const FunctionCallbackInfo<Value>& args) {
426   Environment* env = Environment::GetCurrent(args);
427 
428   if (env->no_native_addons()) {
429     return THROW_ERR_DLOPEN_DISABLED(
430       env, "Cannot load native addon because loading addons is disabled.");
431   }
432 
433   auto context = env->context();
434 
435   CHECK_NULL(thread_local_modpending);
436 
437   if (args.Length() < 2) {
438     return THROW_ERR_MISSING_ARGS(
439         env, "process.dlopen needs at least 2 arguments");
440   }
441 
442   int32_t flags = DLib::kDefaultFlags;
443   if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
444     return THROW_ERR_INVALID_ARG_TYPE(env, "flag argument must be an integer.");
445   }
446 
447   Local<Object> module;
448   Local<Object> exports;
449   Local<Value> exports_v;
450   if (!args[0]->ToObject(context).ToLocal(&module) ||
451       !module->Get(context, env->exports_string()).ToLocal(&exports_v) ||
452       !exports_v->ToObject(context).ToLocal(&exports)) {
453     return;  // Exception pending.
454   }
455 
456   node::Utf8Value filename(env->isolate(), args[1]);  // Cast
457   env->TryLoadAddon(*filename, flags, [&](DLib* dlib) {
458     static Mutex dlib_load_mutex;
459     Mutex::ScopedLock lock(dlib_load_mutex);
460 
461     const bool is_opened = dlib->Open();
462 
463     // Objects containing v14 or later modules will have registered themselves
464     // on the pending list.  Activate all of them now.  At present, only one
465     // module per object is supported.
466     node_module* mp = thread_local_modpending;
467     thread_local_modpending = nullptr;
468 
469     if (!is_opened) {
470       std::string errmsg = dlib->errmsg_.c_str();
471       dlib->Close();
472 #ifdef _WIN32
473       // Windows needs to add the filename into the error message
474       errmsg += *filename;
475 #endif  // _WIN32
476       THROW_ERR_DLOPEN_FAILED(env, "%s", errmsg.c_str());
477       return false;
478     }
479 
480     if (mp != nullptr) {
481       if (mp->nm_context_register_func == nullptr) {
482         if (env->force_context_aware()) {
483           dlib->Close();
484           THROW_ERR_NON_CONTEXT_AWARE_DISABLED(env);
485           return false;
486         }
487       }
488       mp->nm_dso_handle = dlib->handle_;
489       dlib->SaveInGlobalHandleMap(mp);
490     } else {
491       if (auto callback = GetInitializerCallback(dlib)) {
492         callback(exports, module, context);
493         return true;
494       } else if (auto napi_callback = GetNapiInitializerCallback(dlib)) {
495         int32_t module_api_version = NODE_API_DEFAULT_MODULE_API_VERSION;
496         if (auto get_version = GetNapiAddonGetApiVersionCallback(dlib)) {
497           module_api_version = get_version();
498         }
499         napi_module_register_by_symbol(
500             exports, module, context, napi_callback, module_api_version);
501         return true;
502       } else {
503         mp = dlib->GetSavedModuleFromGlobalHandleMap();
504         if (mp == nullptr || mp->nm_context_register_func == nullptr) {
505           dlib->Close();
506           THROW_ERR_DLOPEN_FAILED(
507               env, "Module did not self-register: '%s'.", *filename);
508           return false;
509         }
510       }
511     }
512 
513     // -1 is used for N-API modules
514     if ((mp->nm_version != -1) && (mp->nm_version != NODE_MODULE_VERSION)) {
515       // Even if the module did self-register, it may have done so with the
516       // wrong version. We must only give up after having checked to see if it
517       // has an appropriate initializer callback.
518       if (auto callback = GetInitializerCallback(dlib)) {
519         callback(exports, module, context);
520         return true;
521       }
522 
523       const int actual_nm_version = mp->nm_version;
524       // NOTE: `mp` is allocated inside of the shared library's memory, calling
525       // `dlclose` will deallocate it
526       dlib->Close();
527       THROW_ERR_DLOPEN_FAILED(
528           env,
529           "The module '%s'"
530           "\nwas compiled against a different Node.js version using"
531           "\nNODE_MODULE_VERSION %d. This version of Node.js requires"
532           "\nNODE_MODULE_VERSION %d. Please try re-compiling or "
533           "re-installing\nthe module (for instance, using `npm rebuild` "
534           "or `npm install`).",
535           *filename,
536           actual_nm_version,
537           NODE_MODULE_VERSION);
538       return false;
539     }
540     CHECK_EQ(mp->nm_flags & NM_F_BUILTIN, 0);
541 
542     // Do not keep the lock while running userland addon loading code.
543     Mutex::ScopedUnlock unlock(lock);
544     if (mp->nm_context_register_func != nullptr) {
545       mp->nm_context_register_func(exports, module, context, mp->nm_priv);
546     } else if (mp->nm_register_func != nullptr) {
547       mp->nm_register_func(exports, module, mp->nm_priv);
548     } else {
549       dlib->Close();
550       THROW_ERR_DLOPEN_FAILED(env, "Module has no declared entry point.");
551       return false;
552     }
553 
554     return true;
555   });
556 
557   // Tell coverity that 'handle' should not be freed when we return.
558   // coverity[leaked_storage]
559 }
560 
FindModule(struct node_module * list,const char * name,int flag)561 inline struct node_module* FindModule(struct node_module* list,
562                                       const char* name,
563                                       int flag) {
564   struct node_module* mp;
565 
566   for (mp = list; mp != nullptr; mp = mp->nm_link) {
567     if (strcmp(mp->nm_modname, name) == 0) break;
568   }
569 
570   CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
571   return mp;
572 }
573 
InitInternalBinding(Environment * env,node_module * mod,Local<String> module)574 static Local<Object> InitInternalBinding(Environment* env,
575                                          node_module* mod,
576                                          Local<String> module) {
577   // Internal bindings don't have a "module" object, only exports.
578   Local<Function> ctor = env->binding_data_ctor_template()
579                              ->GetFunction(env->context())
580                              .ToLocalChecked();
581   Local<Object> exports = ctor->NewInstance(env->context()).ToLocalChecked();
582   CHECK_NULL(mod->nm_register_func);
583   CHECK_NOT_NULL(mod->nm_context_register_func);
584   Local<Value> unused = Undefined(env->isolate());
585   mod->nm_context_register_func(exports, unused, env->context(), mod->nm_priv);
586   return exports;
587 }
588 
GetInternalBinding(const FunctionCallbackInfo<Value> & args)589 void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
590   Environment* env = Environment::GetCurrent(args);
591 
592   CHECK(args[0]->IsString());
593 
594   Local<String> module = args[0].As<String>();
595   node::Utf8Value module_v(env->isolate(), module);
596   Local<Object> exports;
597 
598   node_module* mod = FindModule(modlist_internal, *module_v, NM_F_INTERNAL);
599   if (mod != nullptr) {
600     exports = InitInternalBinding(env, mod, module);
601     env->internal_bindings.insert(mod);
602   } else if (!strcmp(*module_v, "constants")) {
603     exports = Object::New(env->isolate());
604     CHECK(
605         exports->SetPrototype(env->context(), Null(env->isolate())).FromJust());
606     DefineConstants(env->isolate(), exports);
607   } else if (!strcmp(*module_v, "natives")) {
608     exports = builtins::BuiltinLoader::GetSourceObject(env->context());
609     // Legacy feature: process.binding('natives').config contains stringified
610     // config.gypi
611     CHECK(exports
612               ->Set(env->context(),
613                     env->config_string(),
614                     builtins::BuiltinLoader::GetConfigString(env->isolate()))
615               .FromJust());
616   } else {
617     return THROW_ERR_INVALID_MODULE(env, "No such binding: %s", *module_v);
618   }
619 
620   args.GetReturnValue().Set(exports);
621 }
622 
GetLinkedBinding(const FunctionCallbackInfo<Value> & args)623 void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
624   Environment* env = Environment::GetCurrent(args);
625 
626   CHECK(args[0]->IsString());
627 
628   Local<String> module_name = args[0].As<String>();
629 
630   node::Utf8Value module_name_v(env->isolate(), module_name);
631   const char* name = *module_name_v;
632   node_module* mod = nullptr;
633 
634   // Iterate from here to the nearest non-Worker Environment to see if there's
635   // a linked binding defined locally rather than through the global list.
636   Environment* cur_env = env;
637   while (mod == nullptr && cur_env != nullptr) {
638     Mutex::ScopedLock lock(cur_env->extra_linked_bindings_mutex());
639     mod = FindModule(cur_env->extra_linked_bindings_head(), name, NM_F_LINKED);
640     cur_env = cur_env->worker_parent_env();
641   }
642 
643   if (mod == nullptr)
644     mod = FindModule(modlist_linked, name, NM_F_LINKED);
645 
646   if (mod == nullptr) {
647     return THROW_ERR_INVALID_MODULE(
648         env, "No such binding was linked: %s", *module_name_v);
649   }
650 
651   Local<Object> module = Object::New(env->isolate());
652   Local<Object> exports = Object::New(env->isolate());
653   Local<String> exports_prop =
654       String::NewFromUtf8Literal(env->isolate(), "exports");
655   module->Set(env->context(), exports_prop, exports).Check();
656 
657   if (mod->nm_context_register_func != nullptr) {
658     mod->nm_context_register_func(
659         exports, module, env->context(), mod->nm_priv);
660   } else if (mod->nm_register_func != nullptr) {
661     mod->nm_register_func(exports, module, mod->nm_priv);
662   } else {
663     return THROW_ERR_INVALID_MODULE(
664         env, "Linked binding has no declared entry point.");
665   }
666 
667   auto effective_exports =
668       module->Get(env->context(), exports_prop).ToLocalChecked();
669 
670   args.GetReturnValue().Set(effective_exports);
671 }
672 
673 // Call built-in bindings' _register_<module name> function to
674 // do binding registration explicitly.
RegisterBuiltinBindings()675 void RegisterBuiltinBindings() {
676 #define V(modname) _register_##modname();
677   NODE_BUILTIN_BINDINGS(V)
678 #undef V
679 }
680 
RegisterExternalReferences(ExternalReferenceRegistry * registry)681 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
682   registry->Register(GetLinkedBinding);
683   registry->Register(GetInternalBinding);
684 }
685 
686 }  // namespace binding
687 }  // namespace node
688 
689 NODE_BINDING_EXTERNAL_REFERENCE(binding,
690                                 node::binding::RegisterExternalReferences)
691