• 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 #define V(modname)                                                             \
114   void _register_isolate_##modname(node::IsolateData* isolate_data,            \
115                                    v8::Local<v8::FunctionTemplate> target);
116 NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V)
117 #undef V
118 
119 #ifdef _AIX
120 // On AIX, dlopen() behaves differently from other operating systems, in that
121 // it returns unique values from each call, rather than identical values, when
122 // loading the same handle.
123 // We try to work around that by providing wrappers for the dlopen() family of
124 // functions, and using st_dev and st_ino for the file that is to be loaded
125 // as keys for a cache.
126 
127 namespace node {
128 namespace dlwrapper {
129 
130 struct dl_wrap {
131   uint64_t st_dev;
132   uint64_t st_ino;
133   uint64_t refcount;
134   void* real_handle;
135 
136   struct hash {
operator ()node::dlwrapper::dl_wrap::hash137     size_t operator()(const dl_wrap* wrap) const {
138       return std::hash<uint64_t>()(wrap->st_dev) ^
139              std::hash<uint64_t>()(wrap->st_ino);
140     }
141   };
142 
143   struct equal {
operator ()node::dlwrapper::dl_wrap::equal144     bool operator()(const dl_wrap* a,
145                     const dl_wrap* b) const {
146       return a->st_dev == b->st_dev && a->st_ino == b->st_ino;
147     }
148   };
149 };
150 
151 static Mutex dlhandles_mutex;
152 static std::unordered_set<dl_wrap*, dl_wrap::hash, dl_wrap::equal>
153     dlhandles;
154 static thread_local std::string dlerror_storage;
155 
wrapped_dlerror()156 char* wrapped_dlerror() {
157   return &dlerror_storage[0];
158 }
159 
wrapped_dlopen(const char * filename,int flags)160 void* wrapped_dlopen(const char* filename, int flags) {
161   CHECK_NOT_NULL(filename);  // This deviates from the 'real' dlopen().
162   Mutex::ScopedLock lock(dlhandles_mutex);
163 
164   uv_fs_t req;
165   auto cleanup = OnScopeLeave([&]() { uv_fs_req_cleanup(&req); });
166   int rc = uv_fs_stat(nullptr, &req, filename, nullptr);
167 
168   if (rc != 0) {
169     dlerror_storage = uv_strerror(rc);
170     return nullptr;
171   }
172 
173   dl_wrap search = {
174     req.statbuf.st_dev,
175     req.statbuf.st_ino,
176     0, nullptr
177   };
178 
179   auto it = dlhandles.find(&search);
180   if (it != dlhandles.end()) {
181     (*it)->refcount++;
182     return *it;
183   }
184 
185   void* real_handle = dlopen(filename, flags);
186   if (real_handle == nullptr) {
187     dlerror_storage = dlerror();
188     return nullptr;
189   }
190   dl_wrap* wrap = new dl_wrap();
191   wrap->st_dev = req.statbuf.st_dev;
192   wrap->st_ino = req.statbuf.st_ino;
193   wrap->refcount = 1;
194   wrap->real_handle = real_handle;
195   dlhandles.insert(wrap);
196   return wrap;
197 }
198 
wrapped_dlclose(void * handle)199 int wrapped_dlclose(void* handle) {
200   Mutex::ScopedLock lock(dlhandles_mutex);
201   dl_wrap* wrap = static_cast<dl_wrap*>(handle);
202   int ret = 0;
203   CHECK_GE(wrap->refcount, 1);
204   if (--wrap->refcount == 0) {
205     ret = dlclose(wrap->real_handle);
206     if (ret != 0) dlerror_storage = dlerror();
207     dlhandles.erase(wrap);
208     delete wrap;
209   }
210   return ret;
211 }
212 
wrapped_dlsym(void * handle,const char * symbol)213 void* wrapped_dlsym(void* handle, const char* symbol) {
214   if (handle == RTLD_DEFAULT || handle == RTLD_NEXT)
215     return dlsym(handle, symbol);
216   dl_wrap* wrap = static_cast<dl_wrap*>(handle);
217   return dlsym(wrap->real_handle, symbol);
218 }
219 
220 #define dlopen node::dlwrapper::wrapped_dlopen
221 #define dlerror node::dlwrapper::wrapped_dlerror
222 #define dlclose node::dlwrapper::wrapped_dlclose
223 #define dlsym node::dlwrapper::wrapped_dlsym
224 
225 }  // namespace dlwrapper
226 }  // namespace node
227 
228 #endif  // _AIX
229 
230 #ifdef __linux__
libc_may_be_musl()231 static bool libc_may_be_musl() {
232   static std::atomic_bool retval;  // Cache the return value.
233   static std::atomic_bool has_cached_retval { false };
234   if (has_cached_retval) return retval;
235   retval = dlsym(RTLD_DEFAULT, "gnu_get_libc_version") == nullptr;
236   has_cached_retval = true;
237   return retval;
238 }
239 #elif defined(__POSIX__)
libc_may_be_musl()240 static bool libc_may_be_musl() { return false; }
241 #endif  // __linux__
242 
243 namespace node {
244 
245 using v8::Context;
246 using v8::EscapableHandleScope;
247 using v8::Exception;
248 using v8::FunctionCallbackInfo;
249 using v8::FunctionTemplate;
250 using v8::HandleScope;
251 using v8::Isolate;
252 using v8::Local;
253 using v8::Object;
254 using v8::String;
255 using v8::Value;
256 
257 // Globals per process
258 static node_module* modlist_internal;
259 static node_module* modlist_linked;
260 static thread_local node_module* thread_local_modpending;
261 
262 // This is set by node::Init() which is used by embedders
263 bool node_is_initialized = false;
264 
node_module_register(void * m)265 extern "C" void node_module_register(void* m) {
266   struct node_module* mp = reinterpret_cast<struct node_module*>(m);
267 
268   if (mp->nm_flags & NM_F_INTERNAL) {
269     mp->nm_link = modlist_internal;
270     modlist_internal = mp;
271   } else if (!node_is_initialized) {
272     // "Linked" modules are included as part of the node project.
273     // Like builtins they are registered *before* node::Init runs.
274     mp->nm_flags = NM_F_LINKED;
275     mp->nm_link = modlist_linked;
276     modlist_linked = mp;
277   } else {
278     thread_local_modpending = mp;
279   }
280 }
281 
282 namespace binding {
283 
284 static struct global_handle_map_t {
285  public:
setnode::binding::global_handle_map_t286   void set(void* handle, node_module* mod) {
287     CHECK_NE(handle, nullptr);
288     Mutex::ScopedLock lock(mutex_);
289 
290     map_[handle].module = mod;
291     // We need to store this flag internally to avoid a chicken-and-egg problem
292     // during cleanup. By the time we actually use the flag's value,
293     // the shared object has been unloaded, and its memory would be gone,
294     // making it impossible to access fields of `mod` --
295     // unless `mod` *is* dynamically allocated, but we cannot know that
296     // without checking the flag.
297     map_[handle].wants_delete_module = mod->nm_flags & NM_F_DELETEME;
298     map_[handle].refcount++;
299   }
300 
get_and_increase_refcountnode::binding::global_handle_map_t301   node_module* get_and_increase_refcount(void* handle) {
302     CHECK_NE(handle, nullptr);
303     Mutex::ScopedLock lock(mutex_);
304 
305     auto it = map_.find(handle);
306     if (it == map_.end()) return nullptr;
307     it->second.refcount++;
308     return it->second.module;
309   }
310 
erasenode::binding::global_handle_map_t311   void erase(void* handle) {
312     CHECK_NE(handle, nullptr);
313     Mutex::ScopedLock lock(mutex_);
314 
315     auto it = map_.find(handle);
316     if (it == map_.end()) return;
317     CHECK_GE(it->second.refcount, 1);
318     if (--it->second.refcount == 0) {
319       if (it->second.wants_delete_module)
320         delete it->second.module;
321       map_.erase(handle);
322     }
323   }
324 
325  private:
326   Mutex mutex_;
327   struct Entry {
328     unsigned int refcount;
329     bool wants_delete_module;
330     node_module* module;
331   };
332   std::unordered_map<void*, Entry> map_;
333 } global_handle_map;
334 
DLib(const char * filename,int flags)335 DLib::DLib(const char* filename, int flags)
336     : filename_(filename), flags_(flags), handle_(nullptr) {}
337 
338 #ifdef __POSIX__
Open()339 bool DLib::Open() {
340   handle_ = dlopen(filename_.c_str(), flags_);
341   if (handle_ != nullptr) return true;
342   errmsg_ = dlerror();
343   return false;
344 }
345 
Close()346 void DLib::Close() {
347   if (handle_ == nullptr) return;
348 
349   if (libc_may_be_musl()) {
350     // musl libc implements dlclose() as a no-op which returns 0.
351     // As a consequence, trying to re-load a previously closed addon at a later
352     // point will not call its static constructors, which Node.js uses.
353     // Therefore, when we may be using musl libc, we assume that the shared
354     // object exists indefinitely and keep it in our handle map.
355     return;
356   }
357 
358   int err = dlclose(handle_);
359   if (err == 0) {
360     if (has_entry_in_global_handle_map_)
361       global_handle_map.erase(handle_);
362   }
363   handle_ = nullptr;
364 }
365 
GetSymbolAddress(const char * name)366 void* DLib::GetSymbolAddress(const char* name) {
367   return dlsym(handle_, name);
368 }
369 #else   // !__POSIX__
Open()370 bool DLib::Open() {
371   int ret = uv_dlopen(filename_.c_str(), &lib_);
372   if (ret == 0) {
373     handle_ = static_cast<void*>(lib_.handle);
374     return true;
375   }
376   errmsg_ = uv_dlerror(&lib_);
377   uv_dlclose(&lib_);
378   return false;
379 }
380 
Close()381 void DLib::Close() {
382   if (handle_ == nullptr) return;
383   if (has_entry_in_global_handle_map_)
384     global_handle_map.erase(handle_);
385   uv_dlclose(&lib_);
386   handle_ = nullptr;
387 }
388 
GetSymbolAddress(const char * name)389 void* DLib::GetSymbolAddress(const char* name) {
390   void* address;
391   if (0 == uv_dlsym(&lib_, name, &address)) return address;
392   return nullptr;
393 }
394 #endif  // !__POSIX__
395 
SaveInGlobalHandleMap(node_module * mp)396 void DLib::SaveInGlobalHandleMap(node_module* mp) {
397   has_entry_in_global_handle_map_ = true;
398   global_handle_map.set(handle_, mp);
399 }
400 
GetSavedModuleFromGlobalHandleMap()401 node_module* DLib::GetSavedModuleFromGlobalHandleMap() {
402   has_entry_in_global_handle_map_ = true;
403   return global_handle_map.get_and_increase_refcount(handle_);
404 }
405 
406 using InitializerCallback = void (*)(Local<Object> exports,
407                                      Local<Value> module,
408                                      Local<Context> context);
409 
GetInitializerCallback(DLib * dlib)410 inline InitializerCallback GetInitializerCallback(DLib* dlib) {
411   const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
412   return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
413 }
414 
GetNapiInitializerCallback(DLib * dlib)415 inline jsvm_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
416   const char* name =
417       STRINGIFY(JSVM_MODULE_INITIALIZER_BASE) STRINGIFY(JSVM_MODULE_VERSION);
418   return reinterpret_cast<jsvm_addon_register_func>(
419       dlib->GetSymbolAddress(name));
420 }
421 
GetNapiAddonGetApiVersionCallback(DLib * dlib)422 inline node_api_addon_get_api_version_func GetNapiAddonGetApiVersionCallback(
423     DLib* dlib) {
424   return reinterpret_cast<node_api_addon_get_api_version_func>(
425       dlib->GetSymbolAddress(STRINGIFY(NODE_API_MODULE_GET_API_VERSION)));
426 }
427 
428 // DLOpen is process.dlopen(module, filename, flags).
429 // Used to load 'module.node' dynamically shared objects.
430 //
431 // FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
432 // when two contexts try to load the same shared object. Maybe have a shadow
433 // cache that's a plain C list or hash table that's shared across contexts?
DLOpen(const FunctionCallbackInfo<Value> & args)434 void DLOpen(const FunctionCallbackInfo<Value>& args) {
435   Environment* env = Environment::GetCurrent(args);
436 
437   if (env->no_native_addons()) {
438     return THROW_ERR_DLOPEN_DISABLED(
439       env, "Cannot load native addon because loading addons is disabled.");
440   }
441 
442   auto context = env->context();
443 
444   CHECK_NULL(thread_local_modpending);
445 
446   if (args.Length() < 2) {
447     return THROW_ERR_MISSING_ARGS(
448         env, "process.dlopen needs at least 2 arguments");
449   }
450 
451   int32_t flags = DLib::kDefaultFlags;
452   if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
453     return THROW_ERR_INVALID_ARG_TYPE(env, "flag argument must be an integer.");
454   }
455 
456   Local<Object> module;
457   Local<Object> exports;
458   Local<Value> exports_v;
459   if (!args[0]->ToObject(context).ToLocal(&module) ||
460       !module->Get(context, env->exports_string()).ToLocal(&exports_v) ||
461       !exports_v->ToObject(context).ToLocal(&exports)) {
462     return;  // Exception pending.
463   }
464 
465   node::Utf8Value filename(env->isolate(), args[1]);  // Cast
466   env->TryLoadAddon(*filename, flags, [&](DLib* dlib) {
467     static Mutex dlib_load_mutex;
468     Mutex::ScopedLock lock(dlib_load_mutex);
469 
470     const bool is_opened = dlib->Open();
471 
472     // Objects containing v14 or later modules will have registered themselves
473     // on the pending list.  Activate all of them now.  At present, only one
474     // module per object is supported.
475     node_module* mp = thread_local_modpending;
476     thread_local_modpending = nullptr;
477 
478     if (!is_opened) {
479       std::string errmsg = dlib->errmsg_.c_str();
480       dlib->Close();
481 #ifdef _WIN32
482       // Windows needs to add the filename into the error message
483       errmsg += *filename;
484 #endif  // _WIN32
485       THROW_ERR_DLOPEN_FAILED(env, "%s", errmsg.c_str());
486       return false;
487     }
488 
489     if (mp != nullptr) {
490       if (mp->nm_context_register_func == nullptr) {
491         if (env->force_context_aware()) {
492           dlib->Close();
493           THROW_ERR_NON_CONTEXT_AWARE_DISABLED(env);
494           return false;
495         }
496       }
497       mp->nm_dso_handle = dlib->handle_;
498       dlib->SaveInGlobalHandleMap(mp);
499     } else {
500       if (auto callback = GetInitializerCallback(dlib)) {
501         callback(exports, module, context);
502         return true;
503       } else if (auto JSVM_Callback = GetNapiInitializerCallback(dlib)) {
504         int32_t module_api_version = NODE_API_DEFAULT_MODULE_API_VERSION;
505         if (auto get_version = GetNapiAddonGetApiVersionCallback(dlib)) {
506           module_api_version = get_version();
507         }
508         jsvm_module_register_by_symbol(
509             exports, module, context, JSVM_Callback, module_api_version);
510         return true;
511       } else {
512         mp = dlib->GetSavedModuleFromGlobalHandleMap();
513         if (mp == nullptr || mp->nm_context_register_func == nullptr) {
514           dlib->Close();
515           THROW_ERR_DLOPEN_FAILED(
516               env, "Module did not self-register: '%s'.", *filename);
517           return false;
518         }
519       }
520     }
521 
522     // -1 is used for N-API modules
523     if ((mp->nm_version != -1) && (mp->nm_version != NODE_MODULE_VERSION)) {
524       // Even if the module did self-register, it may have done so with the
525       // wrong version. We must only give up after having checked to see if it
526       // has an appropriate initializer callback.
527       if (auto callback = GetInitializerCallback(dlib)) {
528         callback(exports, module, context);
529         return true;
530       }
531 
532       const int actual_nm_version = mp->nm_version;
533       // NOTE: `mp` is allocated inside of the shared library's memory, calling
534       // `dlclose` will deallocate it
535       dlib->Close();
536       THROW_ERR_DLOPEN_FAILED(
537           env,
538           "The module '%s'"
539           "\nwas compiled against a different Node.js version using"
540           "\nNODE_MODULE_VERSION %d. This version of Node.js requires"
541           "\nNODE_MODULE_VERSION %d. Please try re-compiling or "
542           "re-installing\nthe module (for instance, using `npm rebuild` "
543           "or `npm install`).",
544           *filename,
545           actual_nm_version,
546           NODE_MODULE_VERSION);
547       return false;
548     }
549     CHECK_EQ(mp->nm_flags & NM_F_BUILTIN, 0);
550 
551     // Do not keep the lock while running userland addon loading code.
552     Mutex::ScopedUnlock unlock(lock);
553     if (mp->nm_context_register_func != nullptr) {
554       mp->nm_context_register_func(exports, module, context, mp->nm_priv);
555     } else if (mp->nm_register_func != nullptr) {
556       mp->nm_register_func(exports, module, mp->nm_priv);
557     } else {
558       dlib->Close();
559       THROW_ERR_DLOPEN_FAILED(env, "Module has no declared entry point.");
560       return false;
561     }
562 
563     return true;
564   });
565 
566   // Tell coverity that 'handle' should not be freed when we return.
567   // coverity[leaked_storage]
568 }
569 
FindModule(struct node_module * list,const char * name,int flag)570 inline struct node_module* FindModule(struct node_module* list,
571                                       const char* name,
572                                       int flag) {
573   struct node_module* mp;
574 
575   for (mp = list; mp != nullptr; mp = mp->nm_link) {
576     if (strcmp(mp->nm_modname, name) == 0) break;
577   }
578 
579   CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
580   return mp;
581 }
582 
CreateInternalBindingTemplates(IsolateData * isolate_data)583 void CreateInternalBindingTemplates(IsolateData* isolate_data) {
584 #define V(modname)                                                             \
585   do {                                                                         \
586     Local<FunctionTemplate> templ =                                            \
587         FunctionTemplate::New(isolate_data->isolate());                        \
588     templ->InstanceTemplate()->SetInternalFieldCount(                          \
589         BaseObject::kInternalFieldCount);                                      \
590     templ->Inherit(BaseObject::GetConstructorTemplate(isolate_data));          \
591     _register_isolate_##modname(isolate_data, templ);                          \
592     isolate_data->set_##modname##_binding(templ);                              \
593   } while (0);
594   NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V)
595 #undef V
596 }
597 
GetInternalBindingExportObject(IsolateData * isolate_data,const char * mod_name,Local<Context> context)598 static Local<Object> GetInternalBindingExportObject(IsolateData* isolate_data,
599                                                     const char* mod_name,
600                                                     Local<Context> context) {
601   Local<FunctionTemplate> ctor;
602 #define V(name)                                                                \
603   if (strcmp(mod_name, #name) == 0) {                                          \
604     ctor = isolate_data->name##_binding();                                     \
605   } else  // NOLINT(readability/braces)
606   NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V)
607 #undef V
608   {
609     ctor = isolate_data->binding_data_ctor_template();
610   }
611 
612   Local<Object> obj = ctor->GetFunction(context)
613                           .ToLocalChecked()
614                           ->NewInstance(context)
615                           .ToLocalChecked();
616   return obj;
617 }
618 
InitInternalBinding(Realm * realm,node_module * mod)619 static Local<Object> InitInternalBinding(Realm* realm, node_module* mod) {
620   EscapableHandleScope scope(realm->isolate());
621   Local<Context> context = realm->context();
622   Local<Object> exports = GetInternalBindingExportObject(
623       realm->isolate_data(), mod->nm_modname, context);
624   CHECK_NULL(mod->nm_register_func);
625   CHECK_NOT_NULL(mod->nm_context_register_func);
626   Local<Value> unused = Undefined(realm->isolate());
627   // Internal bindings don't have a "module" object, only exports.
628   mod->nm_context_register_func(exports, unused, context, mod->nm_priv);
629   return scope.Escape(exports);
630 }
631 
GetInternalBinding(const FunctionCallbackInfo<Value> & args)632 void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
633   Realm* realm = Realm::GetCurrent(args);
634   Isolate* isolate = realm->isolate();
635   HandleScope scope(isolate);
636   Local<Context> context = realm->context();
637 
638   CHECK(args[0]->IsString());
639 
640   Local<String> module = args[0].As<String>();
641   node::Utf8Value module_v(isolate, module);
642   Local<Object> exports;
643 
644   node_module* mod = FindModule(modlist_internal, *module_v, NM_F_INTERNAL);
645   if (mod != nullptr) {
646     exports = InitInternalBinding(realm, mod);
647     realm->internal_bindings.insert(mod);
648   } else if (!strcmp(*module_v, "constants")) {
649     exports = Object::New(isolate);
650     CHECK(exports->SetPrototype(context, Null(isolate)).FromJust());
651     DefineConstants(isolate, exports);
652   } else if (!strcmp(*module_v, "natives")) {
653     exports = realm->env()->builtin_loader()->GetSourceObject(context);
654     // Legacy feature: process.binding('natives').config contains stringified
655     // config.gypi
656     CHECK(exports
657               ->Set(context,
658                     realm->isolate_data()->config_string(),
659                     realm->env()->builtin_loader()->GetConfigString(isolate))
660               .FromJust());
661   } else {
662     return THROW_ERR_INVALID_MODULE(isolate, "No such binding: %s", *module_v);
663   }
664 
665   args.GetReturnValue().Set(exports);
666 }
667 
GetLinkedBinding(const FunctionCallbackInfo<Value> & args)668 void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
669   Environment* env = Environment::GetCurrent(args);
670 
671   CHECK(args[0]->IsString());
672 
673   Local<String> module_name = args[0].As<String>();
674 
675   node::Utf8Value module_name_v(env->isolate(), module_name);
676   const char* name = *module_name_v;
677   node_module* mod = nullptr;
678 
679   // Iterate from here to the nearest non-Worker Environment to see if there's
680   // a linked binding defined locally rather than through the global list.
681   Environment* cur_env = env;
682   while (mod == nullptr && cur_env != nullptr) {
683     Mutex::ScopedLock lock(cur_env->extra_linked_bindings_mutex());
684     mod = FindModule(cur_env->extra_linked_bindings_head(), name, NM_F_LINKED);
685     cur_env = cur_env->worker_parent_env();
686   }
687 
688   if (mod == nullptr)
689     mod = FindModule(modlist_linked, name, NM_F_LINKED);
690 
691   if (mod == nullptr) {
692     return THROW_ERR_INVALID_MODULE(
693         env, "No such binding was linked: %s", *module_name_v);
694   }
695 
696   Local<Object> module = Object::New(env->isolate());
697   Local<Object> exports = Object::New(env->isolate());
698   Local<String> exports_prop =
699       String::NewFromUtf8Literal(env->isolate(), "exports");
700   module->Set(env->context(), exports_prop, exports).Check();
701 
702   if (mod->nm_context_register_func != nullptr) {
703     mod->nm_context_register_func(
704         exports, module, env->context(), mod->nm_priv);
705   } else if (mod->nm_register_func != nullptr) {
706     mod->nm_register_func(exports, module, mod->nm_priv);
707   } else {
708     return THROW_ERR_INVALID_MODULE(
709         env, "Linked binding has no declared entry point.");
710   }
711 
712   auto effective_exports =
713       module->Get(env->context(), exports_prop).ToLocalChecked();
714 
715   args.GetReturnValue().Set(effective_exports);
716 }
717 
718 // Call built-in bindings' _register_<module name> function to
719 // do binding registration explicitly.
RegisterBuiltinBindings()720 void RegisterBuiltinBindings() {
721 #define V(modname) _register_##modname();
722   NODE_BUILTIN_BINDINGS(V)
723 #undef V
724 }
725 
RegisterExternalReferences(ExternalReferenceRegistry * registry)726 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
727   registry->Register(GetLinkedBinding);
728   registry->Register(GetInternalBinding);
729 }
730 
731 }  // namespace binding
732 }  // namespace node
733 
734 NODE_BINDING_EXTERNAL_REFERENCE(binding,
735                                 node::binding::RegisterExternalReferences)
736