GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_binding.cc Lines: 90 166 54.2 %
Date: 2019-02-01 22:03:38 Branches: 48 108 44.4 %

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


118
  if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
221
    return env->ThrowTypeError("flag argument must be an integer.");
222
  }
223
224
  Local<Object> module;
225
  Local<Object> exports;
226
  Local<Value> exports_v;
227


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


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

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

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