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: 113 148 76.4 %
Date: 2019-02-13 22:28:58 Branches: 66 100 66.0 %

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_MODULE_CONTEXT_AWARE_INTERNAL.
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_internal;
105
static node_module* modlist_linked;
106
static node_module* modlist_addon;
107
static uv_once_t init_modpending_once = UV_ONCE_INIT;
108
static uv_key_t thread_local_modpending;
109
110
// This is set by node::Init() which is used by embedders
111
bool node_is_initialized = false;
112
113
207191
extern "C" void node_module_register(void* m) {
114
207191
  struct node_module* mp = reinterpret_cast<struct node_module*>(m);
115
116
207191
  if (mp->nm_flags & NM_F_INTERNAL) {
117
207072
    mp->nm_link = modlist_internal;
118
207072
    modlist_internal = mp;
119
119
  } else if (!node_is_initialized) {
120
    // "Linked" modules are included as part of the node project.
121
    // Like builtins they are registered *before* node::Init runs.
122
    mp->nm_flags = NM_F_LINKED;
123
    mp->nm_link = modlist_linked;
124
    modlist_linked = mp;
125
  } else {
126
119
    uv_key_set(&thread_local_modpending, mp);
127
  }
128
207191
}
129
130
namespace binding {
131
132
126
DLib::DLib(const char* filename, int flags)
133
126
    : filename_(filename), flags_(flags), handle_(nullptr) {}
134
135
#ifdef __POSIX__
136
126
bool DLib::Open() {
137
126
  handle_ = dlopen(filename_.c_str(), flags_);
138
126
  if (handle_ != nullptr) return true;
139
3
  errmsg_ = dlerror();
140
3
  return false;
141
}
142
143
8
void DLib::Close() {
144
16
  if (handle_ == nullptr) return;
145
5
  dlclose(handle_);
146
5
  handle_ = nullptr;
147
}
148
149
10
void* DLib::GetSymbolAddress(const char* name) {
150
10
  return dlsym(handle_, name);
151
}
152
#else   // !__POSIX__
153
bool DLib::Open() {
154
  int ret = uv_dlopen(filename_.c_str(), &lib_);
155
  if (ret == 0) {
156
    handle_ = static_cast<void*>(lib_.handle);
157
    return true;
158
  }
159
  errmsg_ = uv_dlerror(&lib_);
160
  uv_dlclose(&lib_);
161
  return false;
162
}
163
164
void DLib::Close() {
165
  if (handle_ == nullptr) return;
166
  uv_dlclose(&lib_);
167
  handle_ = nullptr;
168
}
169
170
void* DLib::GetSymbolAddress(const char* name) {
171
  void* address;
172
  if (0 == uv_dlsym(&lib_, name, &address)) return address;
173
  return nullptr;
174
}
175
#endif  // !__POSIX__
176
177
using InitializerCallback = void (*)(Local<Object> exports,
178
                                     Local<Value> module,
179
                                     Local<Context> context);
180
181
7
inline InitializerCallback GetInitializerCallback(DLib* dlib) {
182
7
  const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
183
7
  return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
184
}
185
186
3
inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
187
  const char* name =
188
3
      STRINGIFY(NAPI_MODULE_INITIALIZER_BASE) STRINGIFY(NAPI_MODULE_VERSION);
189
  return reinterpret_cast<napi_addon_register_func>(
190
3
      dlib->GetSymbolAddress(name));
191
}
192
193
118
void InitModpendingOnce() {
194
118
  CHECK_EQ(0, uv_key_create(&thread_local_modpending));
195
118
}
196
197
// DLOpen is process.dlopen(module, filename, flags).
198
// Used to load 'module.node' dynamically shared objects.
199
//
200
// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
201
// when two contexts try to load the same shared object. Maybe have a shadow
202
// cache that's a plain C list or hash table that's shared across contexts?
203
127
void DLOpen(const FunctionCallbackInfo<Value>& args) {
204
127
  Environment* env = Environment::GetCurrent(args);
205
127
  auto context = env->context();
206
207
127
  uv_once(&init_modpending_once, InitModpendingOnce);
208
127
  CHECK_NULL(uv_key_get(&thread_local_modpending));
209
210
127
  if (args.Length() < 2) {
211
    env->ThrowError("process.dlopen needs at least 2 arguments.");
212
    return;
213
  }
214
215
127
  int32_t flags = DLib::kDefaultFlags;
216


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


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


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

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

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