GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_binding.cc Lines: 128 167 76.6 %
Date: 2019-01-07 12:15:22 Branches: 70 108 64.8 %

Line Branch Exec Source
1
#include "node_binding.h"
2
#include "node_internals.h"
3
#include "node_native_module.h"
4
5
#if HAVE_OPENSSL
6
#define NODE_BUILTIN_OPENSSL_MODULES(V) V(crypto) V(tls_wrap)
7
#else
8
#define NODE_BUILTIN_OPENSSL_MODULES(V)
9
#endif
10
11
#if NODE_HAVE_I18N_SUPPORT
12
#define NODE_BUILTIN_ICU_MODULES(V) V(icu)
13
#else
14
#define NODE_BUILTIN_ICU_MODULES(V)
15
#endif
16
17
// A list of built-in modules. In order to do module registration
18
// in node::Init(), need to add built-in modules in the following list.
19
// Then in binding::RegisterBuiltinModules(), it calls modules' registration
20
// function. This helps the built-in modules are loaded properly when
21
// node is built as static library. No need to depend on the
22
// __attribute__((constructor)) like mechanism in GCC.
23
#define NODE_BUILTIN_STANDARD_MODULES(V)                                       \
24
  V(async_wrap)                                                                \
25
  V(buffer)                                                                    \
26
  V(cares_wrap)                                                                \
27
  V(config)                                                                    \
28
  V(contextify)                                                                \
29
  V(credentials)                                                               \
30
  V(domain)                                                                    \
31
  V(fs)                                                                        \
32
  V(fs_event_wrap)                                                             \
33
  V(heap_utils)                                                                \
34
  V(http2)                                                                     \
35
  V(http_parser)                                                               \
36
  V(http_parser_llhttp)                                                        \
37
  V(inspector)                                                                 \
38
  V(js_stream)                                                                 \
39
  V(messaging)                                                                 \
40
  V(module_wrap)                                                               \
41
  V(native_module)                                                             \
42
  V(options)                                                                   \
43
  V(os)                                                                        \
44
  V(performance)                                                               \
45
  V(pipe_wrap)                                                                 \
46
  V(process_wrap)                                                              \
47
  V(process_methods)                                                           \
48
  V(serdes)                                                                    \
49
  V(signal_wrap)                                                               \
50
  V(spawn_sync)                                                                \
51
  V(stream_pipe)                                                               \
52
  V(stream_wrap)                                                               \
53
  V(string_decoder)                                                            \
54
  V(symbols)                                                                   \
55
  V(task_queue)                                                                \
56
  V(tcp_wrap)                                                                  \
57
  V(timers)                                                                    \
58
  V(trace_events)                                                              \
59
  V(tty_wrap)                                                                  \
60
  V(types)                                                                     \
61
  V(udp_wrap)                                                                  \
62
  V(url)                                                                       \
63
  V(util)                                                                      \
64
  V(uv)                                                                        \
65
  V(v8)                                                                        \
66
  V(worker)                                                                    \
67
  V(zlib)
68
69
#define NODE_BUILTIN_MODULES(V)                                                \
70
  NODE_BUILTIN_STANDARD_MODULES(V)                                             \
71
  NODE_BUILTIN_OPENSSL_MODULES(V)                                              \
72
  NODE_BUILTIN_ICU_MODULES(V)
73
74
// This is used to load built-in modules. Instead of using
75
// __attribute__((constructor)), we call the _register_<modname>
76
// function for each built-in modules explicitly in
77
// binding::RegisterBuiltinModules(). This is only forward declaration.
78
// The definitions are in each module's implementation when calling
79
// the NODE_BUILTIN_MODULE_CONTEXT_AWARE.
80
#define V(modname) void _register_##modname();
81
NODE_BUILTIN_MODULES(V)
82
#undef V
83
84
namespace node {
85
86
using v8::Context;
87
using v8::Exception;
88
using v8::FunctionCallbackInfo;
89
using v8::Local;
90
using v8::NewStringType;
91
using v8::Object;
92
using v8::String;
93
using v8::Value;
94
95
// Globals per process
96
static node_module* modlist_builtin;
97
static node_module* modlist_internal;
98
static node_module* modlist_linked;
99
static node_module* modlist_addon;
100
static uv_once_t init_modpending_once = UV_ONCE_INIT;
101
static uv_key_t thread_local_modpending;
102
103
// This is set by node::Init() which is used by embedders
104
bool node_is_initialized = false;
105
106
169122
extern "C" void node_module_register(void* m) {
107
169122
  struct node_module* mp = reinterpret_cast<struct node_module*>(m);
108
109
169122
  if (mp->nm_flags & NM_F_BUILTIN) {
110
    mp->nm_link = modlist_builtin;
111
    modlist_builtin = mp;
112
169122
  } else if (mp->nm_flags & NM_F_INTERNAL) {
113
169012
    mp->nm_link = modlist_internal;
114
169012
    modlist_internal = mp;
115
110
  } else if (!node_is_initialized) {
116
    // "Linked" modules are included as part of the node project.
117
    // Like builtins they are registered *before* node::Init runs.
118
    mp->nm_flags = NM_F_LINKED;
119
    mp->nm_link = modlist_linked;
120
    modlist_linked = mp;
121
  } else {
122
110
    uv_key_set(&thread_local_modpending, mp);
123
  }
124
169122
}
125
126
namespace binding {
127
128
117
DLib::DLib(const char* filename, int flags)
129
117
    : filename_(filename), flags_(flags), handle_(nullptr) {}
130
131
#ifdef __POSIX__
132
117
bool DLib::Open() {
133
117
  handle_ = dlopen(filename_.c_str(), flags_);
134
117
  if (handle_ != nullptr) return true;
135
3
  errmsg_ = dlerror();
136
3
  return false;
137
}
138
139
116
void DLib::Close() {
140
232
  if (handle_ == nullptr) return;
141
113
  dlclose(handle_);
142
113
  handle_ = nullptr;
143
}
144
145
10
void* DLib::GetSymbolAddress(const char* name) {
146
10
  return dlsym(handle_, name);
147
}
148
#else   // !__POSIX__
149
bool DLib::Open() {
150
  int ret = uv_dlopen(filename_.c_str(), &lib_);
151
  if (ret == 0) {
152
    handle_ = static_cast<void*>(lib_.handle);
153
    return true;
154
  }
155
  errmsg_ = uv_dlerror(&lib_);
156
  uv_dlclose(&lib_);
157
  return false;
158
}
159
160
void DLib::Close() {
161
  if (handle_ == nullptr) return;
162
  uv_dlclose(&lib_);
163
  handle_ = nullptr;
164
}
165
166
void* DLib::GetSymbolAddress(const char* name) {
167
  void* address;
168
  if (0 == uv_dlsym(&lib_, name, &address)) return address;
169
  return nullptr;
170
}
171
#endif  // !__POSIX__
172
173
using InitializerCallback = void (*)(Local<Object> exports,
174
                                     Local<Value> module,
175
                                     Local<Context> context);
176
177
7
inline InitializerCallback GetInitializerCallback(DLib* dlib) {
178
7
  const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
179
7
  return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
180
}
181
182
3
inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
183
  const char* name =
184
3
      STRINGIFY(NAPI_MODULE_INITIALIZER_BASE) STRINGIFY(NAPI_MODULE_VERSION);
185
  return reinterpret_cast<napi_addon_register_func>(
186
3
      dlib->GetSymbolAddress(name));
187
}
188
189
113
void InitModpendingOnce() {
190
113
  CHECK_EQ(0, uv_key_create(&thread_local_modpending));
191
113
}
192
193
// DLOpen is process.dlopen(module, filename, flags).
194
// Used to load 'module.node' dynamically shared objects.
195
//
196
// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
197
// when two contexts try to load the same shared object. Maybe have a shadow
198
// cache that's a plain C list or hash table that's shared across contexts?
199
118
void DLOpen(const FunctionCallbackInfo<Value>& args) {
200
118
  Environment* env = Environment::GetCurrent(args);
201
118
  auto context = env->context();
202
203
118
  uv_once(&init_modpending_once, InitModpendingOnce);
204
118
  CHECK_NULL(uv_key_get(&thread_local_modpending));
205
206
118
  if (args.Length() < 2) {
207
    env->ThrowError("process.dlopen needs at least 2 arguments.");
208
    return;
209
  }
210
211
118
  int32_t flags = DLib::kDefaultFlags;
212


239
  if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
213
    return env->ThrowTypeError("flag argument must be an integer.");
214
  }
215
216
  Local<Object> module;
217
  Local<Object> exports;
218
  Local<Value> exports_v;
219


826
  if (!args[0]->ToObject(context).ToLocal(&module) ||
220


1062
      !module->Get(context, env->exports_string()).ToLocal(&exports_v) ||
221
354
      !exports_v->ToObject(context).ToLocal(&exports)) {
222
1
    return;  // Exception pending.
223
  }
224
225
117
  node::Utf8Value filename(env->isolate(), args[1]);  // Cast
226
234
  env->TryLoadAddon(*filename, flags, [&](DLib* dlib) {
227
117
    const bool is_opened = dlib->Open();
228
229
    // Objects containing v14 or later modules will have registered themselves
230
    // on the pending list.  Activate all of them now.  At present, only one
231
    // module per object is supported.
232
    node_module* const mp =
233
117
        static_cast<node_module*>(uv_key_get(&thread_local_modpending));
234
117
    uv_key_set(&thread_local_modpending, nullptr);
235
236
117
    if (!is_opened) {
237
      Local<String> errmsg =
238
3
          OneByteString(env->isolate(), dlib->errmsg_.c_str());
239
3
      dlib->Close();
240
#ifdef _WIN32
241
      // Windows needs to add the filename into the error message
242
      errmsg = String::Concat(
243
          env->isolate(), errmsg, args[1]->ToString(context).ToLocalChecked());
244
#endif  // _WIN32
245
3
      env->isolate()->ThrowException(Exception::Error(errmsg));
246
3
      return false;
247
    }
248
249
114
    if (mp == nullptr) {
250
4
      if (auto callback = GetInitializerCallback(dlib)) {
251
2
        callback(exports, module, context);
252
3
      } else if (auto napi_callback = GetNapiInitializerCallback(dlib)) {
253
2
        napi_module_register_by_symbol(exports, module, context, napi_callback);
254
      } else {
255
2
        dlib->Close();
256
2
        env->ThrowError("Module did not self-register.");
257
2
        return false;
258
      }
259
2
      return true;
260
    }
261
262
    // -1 is used for N-API modules
263

110
    if ((mp->nm_version != -1) && (mp->nm_version != NODE_MODULE_VERSION)) {
264
      // Even if the module did self-register, it may have done so with the
265
      // wrong version. We must only give up after having checked to see if it
266
      // has an appropriate initializer callback.
267
3
      if (auto callback = GetInitializerCallback(dlib)) {
268
4
        callback(exports, module, context);
269
2
        return true;
270
      }
271
      char errmsg[1024];
272
      snprintf(errmsg,
273
               sizeof(errmsg),
274
               "The module '%s'"
275
               "\nwas compiled against a different Node.js version using"
276
               "\nNODE_MODULE_VERSION %d. This version of Node.js requires"
277
               "\nNODE_MODULE_VERSION %d. Please try re-compiling or "
278
               "re-installing\nthe module (for instance, using `npm rebuild` "
279
               "or `npm install`).",
280
               *filename,
281
               mp->nm_version,
282
1
               NODE_MODULE_VERSION);
283
284
      // NOTE: `mp` is allocated inside of the shared library's memory, calling
285
      // `dlclose` will deallocate it
286
1
      dlib->Close();
287
1
      env->ThrowError(errmsg);
288
1
      return false;
289
    }
290
107
    if (mp->nm_flags & NM_F_BUILTIN) {
291
      dlib->Close();
292
      env->ThrowError("Built-in module self-registered.");
293
      return false;
294
    }
295
296
107
    mp->nm_dso_handle = dlib->handle_;
297
107
    mp->nm_link = modlist_addon;
298
107
    modlist_addon = mp;
299
300
107
    if (mp->nm_context_register_func != nullptr) {
301
132
      mp->nm_context_register_func(exports, module, context, mp->nm_priv);
302
41
    } else if (mp->nm_register_func != nullptr) {
303
82
      mp->nm_register_func(exports, module, mp->nm_priv);
304
    } else {
305
      dlib->Close();
306
      env->ThrowError("Module has no declared entry point.");
307
      return false;
308
    }
309
310
107
    return true;
311
234
  });
312
313
  // Tell coverity that 'handle' should not be freed when we return.
314
  // coverity[leaked_storage]
315
}
316
317
109507
inline struct node_module* FindModule(struct node_module* list,
318
                                      const char* name,
319
                                      int flag) {
320
  struct node_module* mp;
321
322
2723691
  for (mp = list; mp != nullptr; mp = mp->nm_link) {
323
2720009
    if (strcmp(mp->nm_modname, name) == 0) break;
324
  }
325
326

109507
  CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
327
109507
  return mp;
328
}
329
330
2
node_module* get_builtin_module(const char* name) {
331
2
  return FindModule(modlist_builtin, name, NM_F_BUILTIN);
332
}
333
109505
node_module* get_internal_module(const char* name) {
334
109505
  return FindModule(modlist_internal, name, NM_F_INTERNAL);
335
}
336
node_module* get_linked_module(const char* name) {
337
  return FindModule(modlist_linked, name, NM_F_LINKED);
338
}
339
340
105825
static Local<Object> InitModule(Environment* env,
341
                                node_module* mod,
342
                                Local<String> module) {
343
105825
  Local<Object> exports = Object::New(env->isolate());
344
  // Internal bindings don't have a "module" object, only exports.
345
105825
  CHECK_NULL(mod->nm_register_func);
346
105825
  CHECK_NOT_NULL(mod->nm_context_register_func);
347
105825
  Local<Value> unused = Undefined(env->isolate());
348
105825
  mod->nm_context_register_func(exports, unused, env->context(), mod->nm_priv);
349
105825
  return exports;
350
}
351
352
2
static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
353
  char errmsg[1024];
354
2
  snprintf(errmsg, sizeof(errmsg), "No such module: %s", module_v);
355
2
  env->ThrowError(errmsg);
356
2
}
357
358
2
void GetBinding(const FunctionCallbackInfo<Value>& args) {
359
2
  Environment* env = Environment::GetCurrent(args);
360
361
6
  CHECK(args[0]->IsString());
362
363
4
  Local<String> module = args[0].As<String>();
364
2
  node::Utf8Value module_v(env->isolate(), module);
365
366
2
  node_module* mod = get_builtin_module(*module_v);
367
  Local<Object> exports;
368
2
  if (mod != nullptr) {
369
    exports = InitModule(env, mod, module);
370
  } else {
371
4
    return ThrowIfNoSuchModule(env, *module_v);
372
  }
373
374
  args.GetReturnValue().Set(exports);
375
}
376
377
109505
void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
378
109505
  Environment* env = Environment::GetCurrent(args);
379
380
328515
  CHECK(args[0]->IsString());
381
382
219010
  Local<String> module = args[0].As<String>();
383
109505
  node::Utf8Value module_v(env->isolate(), module);
384
  Local<Object> exports;
385
386
109505
  node_module* mod = get_internal_module(*module_v);
387
109505
  if (mod != nullptr) {
388
105825
    exports = InitModule(env, mod, module);
389
3680
  } else if (!strcmp(*module_v, "constants")) {
390
3661
    exports = Object::New(env->isolate());
391
14644
    CHECK(
392
        exports->SetPrototype(env->context(), Null(env->isolate())).FromJust());
393
3661
    DefineConstants(env->isolate(), exports);
394
19
  } else if (!strcmp(*module_v, "natives")) {
395
19
    exports = per_process::native_module_loader.GetSourceObject(env->context());
396
    // Legacy feature: process.binding('natives').config contains stringified
397
    // config.gypi
398
95
    CHECK(exports
399
              ->Set(env->context(),
400
                    env->config_string(),
401
                    per_process::native_module_loader.GetConfigString(
402
                        env->isolate()))
403
              .FromJust());
404
  } else {
405
109505
    return ThrowIfNoSuchModule(env, *module_v);
406
  }
407
408
219010
  args.GetReturnValue().Set(exports);
409
}
410
411
void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
412
  Environment* env = Environment::GetCurrent(args);
413
414
  CHECK(args[0]->IsString());
415
416
  Local<String> module_name = args[0].As<String>();
417
418
  node::Utf8Value module_name_v(env->isolate(), module_name);
419
  node_module* mod = get_linked_module(*module_name_v);
420
421
  if (mod == nullptr) {
422
    char errmsg[1024];
423
    snprintf(errmsg,
424
             sizeof(errmsg),
425
             "No such module was linked: %s",
426
             *module_name_v);
427
    return env->ThrowError(errmsg);
428
  }
429
430
  Local<Object> module = Object::New(env->isolate());
431
  Local<Object> exports = Object::New(env->isolate());
432
  Local<String> exports_prop =
433
      String::NewFromUtf8(env->isolate(), "exports", NewStringType::kNormal)
434
          .ToLocalChecked();
435
  module->Set(env->context(), exports_prop, exports).FromJust();
436
437
  if (mod->nm_context_register_func != nullptr) {
438
    mod->nm_context_register_func(
439
        exports, module, env->context(), mod->nm_priv);
440
  } else if (mod->nm_register_func != nullptr) {
441
    mod->nm_register_func(exports, module, mod->nm_priv);
442
  } else {
443
    return env->ThrowError("Linked module has no declared entry point.");
444
  }
445
446
  auto effective_exports =
447
      module->Get(env->context(), exports_prop).ToLocalChecked();
448
449
  args.GetReturnValue().Set(effective_exports);
450
}
451
452
// Call built-in modules' _register_<module name> function to
453
// do module registration explicitly.
454
3596
void RegisterBuiltinModules() {
455
#define V(modname) _register_##modname();
456
3596
  NODE_BUILTIN_MODULES(V)
457
#undef V
458
3596
}
459
460
}  // namespace binding
461
}  // namespace node