GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_process_methods.cc Lines: 194 213 91.1 %
Date: 2020-05-27 22:15:15 Branches: 68 102 66.7 %

Line Branch Exec Source
1
#include "base_object-inl.h"
2
#include "debug_utils-inl.h"
3
#include "env-inl.h"
4
#include "node.h"
5
#include "node_errors.h"
6
#include "node_internals.h"
7
#include "node_process.h"
8
#include "util-inl.h"
9
#include "uv.h"
10
#include "v8.h"
11
12
#include <vector>
13
14
#if HAVE_INSPECTOR
15
#include "inspector_io.h"
16
#endif
17
18
#include <climits>  // PATH_MAX
19
#include <cstdio>
20
21
#if defined(_MSC_VER)
22
#include <direct.h>
23
#include <io.h>
24
#define umask _umask
25
typedef int mode_t;
26
#else
27
#include <pthread.h>
28
#include <sys/resource.h>  // getrlimit, setrlimit
29
#include <termios.h>  // tcgetattr, tcsetattr
30
#endif
31
32
namespace node {
33
34
using v8::Array;
35
using v8::ArrayBuffer;
36
using v8::BigUint64Array;
37
using v8::Context;
38
using v8::Float64Array;
39
using v8::Function;
40
using v8::FunctionCallbackInfo;
41
using v8::HeapStatistics;
42
using v8::Integer;
43
using v8::Isolate;
44
using v8::Local;
45
using v8::Name;
46
using v8::NewStringType;
47
using v8::Number;
48
using v8::Object;
49
using v8::String;
50
using v8::Uint32;
51
using v8::Uint32Array;
52
using v8::Value;
53
54
namespace per_process {
55
4326
Mutex umask_mutex;
56
}   // namespace per_process
57
58
// Microseconds in a second, as a float, used in CPUUsage() below
59
#define MICROS_PER_SEC 1e6
60
// used in Hrtime() and Uptime() below
61
#define NANOS_PER_SEC 1000000000
62
63
static void Abort(const FunctionCallbackInfo<Value>& args) {
64
  Abort();
65
}
66
67
// For internal testing only, not exposed to userland.
68
static void CauseSegfault(const FunctionCallbackInfo<Value>& args) {
69
  // This should crash hard all platforms.
70
  volatile void** d = static_cast<volatile void**>(nullptr);
71
  *d = nullptr;
72
}
73
74
397
static void Chdir(const FunctionCallbackInfo<Value>& args) {
75
397
  Environment* env = Environment::GetCurrent(args);
76
397
  CHECK(env->owns_process_state());
77
78
397
  CHECK_EQ(args.Length(), 1);
79
1191
  CHECK(args[0]->IsString());
80
793
  Utf8Value path(env->isolate(), args[0]);
81
397
  int err = uv_chdir(*path);
82
397
  if (err) {
83
    // Also include the original working directory, since that will usually
84
    // be helpful information when debugging a `chdir()` failure.
85
    char buf[PATH_MAX_BYTES];
86
1
    size_t cwd_len = sizeof(buf);
87
1
    uv_cwd(buf, &cwd_len);
88
1
    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
89
  }
90
}
91
92
// CPUUsage use libuv's uv_getrusage() this-process resource usage accessor,
93
// to access ru_utime (user CPU time used) and ru_stime (system CPU time used),
94
// which are uv_timeval_t structs (long tv_sec, long tv_usec).
95
// Returns those values as Float64 microseconds in the elements of the array
96
// passed to the function.
97
33
static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
98
  uv_rusage_t rusage;
99
100
  // Call libuv to get the values we'll return.
101
33
  int err = uv_getrusage(&rusage);
102
33
  if (err) {
103
    // On error, return the strerror version of the error code.
104
    Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err));
105
    return args.GetReturnValue().Set(errmsg);
106
  }
107
108
  // Get the double array pointer from the Float64Array argument.
109
66
  CHECK(args[0]->IsFloat64Array());
110
66
  Local<Float64Array> array = args[0].As<Float64Array>();
111
33
  CHECK_EQ(array->Length(), 2);
112
33
  Local<ArrayBuffer> ab = array->Buffer();
113
33
  double* fields = static_cast<double*>(ab->GetBackingStore()->Data());
114
115
  // Set the Float64Array elements to be user / system values in microseconds.
116
33
  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
117
33
  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
118
}
119
120
4997
static void Cwd(const FunctionCallbackInfo<Value>& args) {
121
4997
  Environment* env = Environment::GetCurrent(args);
122
4997
  CHECK(env->has_run_bootstrapping_code());
123
  char buf[PATH_MAX_BYTES];
124
4997
  size_t cwd_len = sizeof(buf);
125
4997
  int err = uv_cwd(buf, &cwd_len);
126
4997
  if (err)
127
12
    return env->ThrowUVException(err, "uv_cwd");
128
129
9970
  Local<String> cwd = String::NewFromUtf8(env->isolate(),
130
                                          buf,
131
                                          NewStringType::kNormal,
132
9970
                                          cwd_len).ToLocalChecked();
133
9970
  args.GetReturnValue().Set(cwd);
134
}
135
136
137
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
138
139
// This is the legacy version of hrtime before BigInt was introduced in
140
// JavaScript.
141
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
142
// so this function instead fills in an Uint32Array with 3 entries,
143
// to avoid any integer overflow possibility.
144
// The first two entries contain the second part of the value
145
// broken into the upper/lower 32 bits to be converted back in JS,
146
// because there is no Uint64Array in JS.
147
// The third entry contains the remaining nanosecond part of the value.
148
83095
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
149
83095
  uint64_t t = uv_hrtime();
150
151
249285
  Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
152
83095
  uint32_t* fields = static_cast<uint32_t*>(ab->GetBackingStore()->Data());
153
154
83095
  fields[0] = (t / NANOS_PER_SEC) >> 32;
155
83095
  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
156
83095
  fields[2] = t % NANOS_PER_SEC;
157
83095
}
158
159
729393
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
160
2188179
  Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
161
729393
  uint64_t* fields = static_cast<uint64_t*>(ab->GetBackingStore()->Data());
162
729393
  fields[0] = uv_hrtime();
163
729393
}
164
165
63
static void Kill(const FunctionCallbackInfo<Value>& args) {
166
63
  Environment* env = Environment::GetCurrent(args);
167
63
  Local<Context> context = env->context();
168
169
63
  if (args.Length() != 2)
170
    return env->ThrowError("Bad argument.");
171
172
  int pid;
173
189
  if (!args[0]->Int32Value(context).To(&pid)) return;
174
  int sig;
175
189
  if (!args[1]->Int32Value(context).To(&sig)) return;
176
177
63
  uv_pid_t own_pid = uv_os_getpid();
178

187
  if (sig > 0 &&
179


150
      (pid == 0 || pid == -1 || pid == own_pid || pid == -own_pid) &&
180
27
      !HasSignalJSHandler(sig)) {
181
    // This is most likely going to terminate this process.
182
    // It's not an exact method but it might be close enough.
183
18
    RunAtExit(env);
184
  }
185
186
63
  int err = uv_kill(pid, sig);
187
126
  args.GetReturnValue().Set(err);
188
}
189
190
527
static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
191
527
  Environment* env = Environment::GetCurrent(args);
192
193
  size_t rss;
194
527
  int err = uv_resident_set_memory(&rss);
195
527
  if (err)
196
    return env->ThrowUVException(err, "uv_resident_set_memory");
197
198
527
  Isolate* isolate = env->isolate();
199
  // V8 memory usage
200
527
  HeapStatistics v8_heap_stats;
201
527
  isolate->GetHeapStatistics(&v8_heap_stats);
202
203
  NodeArrayBufferAllocator* array_buffer_allocator =
204
527
      env->isolate_data()->node_allocator();
205
206
  // Get the double array pointer from the Float64Array argument.
207
1054
  CHECK(args[0]->IsFloat64Array());
208
1054
  Local<Float64Array> array = args[0].As<Float64Array>();
209
527
  CHECK_EQ(array->Length(), 5);
210
527
  Local<ArrayBuffer> ab = array->Buffer();
211
527
  double* fields = static_cast<double*>(ab->GetBackingStore()->Data());
212
213
527
  fields[0] = rss;
214
527
  fields[1] = v8_heap_stats.total_heap_size();
215
527
  fields[2] = v8_heap_stats.used_heap_size();
216
527
  fields[3] = v8_heap_stats.external_memory();
217
1054
  fields[4] = array_buffer_allocator == nullptr ?
218
527
      0 : array_buffer_allocator->total_mem_usage();
219
}
220
221
13
void RawDebug(const FunctionCallbackInfo<Value>& args) {
222


52
  CHECK(args.Length() == 1 && args[0]->IsString() &&
223
        "must be called with a single string");
224
26
  Utf8Value message(args.GetIsolate(), args[0]);
225
13
  FPrintF(stderr, "%s\n", message);
226
13
  fflush(stderr);
227
13
}
228
229
static void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
230
  Environment* env = Environment::GetCurrent(args);
231
  env->StartProfilerIdleNotifier();
232
}
233
234
static void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
235
  Environment* env = Environment::GetCurrent(args);
236
  env->StopProfilerIdleNotifier();
237
}
238
239
3730
static void Umask(const FunctionCallbackInfo<Value>& args) {
240
3730
  Environment* env = Environment::GetCurrent(args);
241
3730
  CHECK(env->has_run_bootstrapping_code());
242
3730
  CHECK_EQ(args.Length(), 1);
243

18290
  CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
244
7460
  Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
245
246
  uint32_t old;
247
11190
  if (args[0]->IsUndefined()) {
248
180
    if (env->emit_insecure_umask_warning()) {
249
5
      env->set_emit_insecure_umask_warning(false);
250
10
      if (ProcessEmitDeprecationWarning(
251
              env,
252
              "Calling process.umask() with no arguments is prone to race "
253
              "conditions and is a potential security vulnerability.",
254
              "DEP0139").IsNothing()) {
255
        return;
256
      }
257
    }
258
259
180
    old = umask(0);
260
180
    umask(static_cast<mode_t>(old));
261
  } else {
262
10650
    int oct = args[0].As<Uint32>()->Value();
263
3550
    old = umask(static_cast<mode_t>(oct));
264
  }
265
266
7460
  args.GetReturnValue().Set(old);
267
}
268
269
4
static void Uptime(const FunctionCallbackInfo<Value>& args) {
270
4
  Environment* env = Environment::GetCurrent(args);
271
272
4
  uv_update_time(env->event_loop());
273
  double uptime =
274
4
      static_cast<double>(uv_hrtime() - per_process::node_start_time);
275
4
  Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC);
276
8
  args.GetReturnValue().Set(result);
277
4
}
278
279
1
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
280
1
  Environment* env = Environment::GetCurrent(args);
281
282
2
  std::vector<Local<Value>> request_v;
283
13
  for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
284
12
    AsyncWrap* w = req_wrap->GetAsyncWrap();
285
24
    if (w->persistent().IsEmpty())
286
      continue;
287
12
    request_v.emplace_back(w->GetOwner());
288
  }
289
290
3
  args.GetReturnValue().Set(
291
      Array::New(env->isolate(), request_v.data(), request_v.size()));
292
1
}
293
294
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
295
// implemented here for consistency with GetActiveRequests().
296
4
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
297
4
  Environment* env = Environment::GetCurrent(args);
298
299
8
  std::vector<Local<Value>> handle_v;
300
24
  for (auto w : *env->handle_wrap_queue()) {
301
20
    if (!HandleWrap::HasRef(w))
302
1
      continue;
303
19
    handle_v.emplace_back(w->GetOwner());
304
  }
305
12
  args.GetReturnValue().Set(
306
      Array::New(env->isolate(), handle_v.data(), handle_v.size()));
307
4
}
308
309
1
static void ResourceUsage(const FunctionCallbackInfo<Value>& args) {
310
1
  Environment* env = Environment::GetCurrent(args);
311
312
  uv_rusage_t rusage;
313
1
  int err = uv_getrusage(&rusage);
314
1
  if (err)
315
    return env->ThrowUVException(err, "uv_getrusage");
316
317
2
  CHECK(args[0]->IsFloat64Array());
318
2
  Local<Float64Array> array = args[0].As<Float64Array>();
319
1
  CHECK_EQ(array->Length(), 16);
320
1
  Local<ArrayBuffer> ab = array->Buffer();
321
1
  double* fields = static_cast<double*>(ab->GetBackingStore()->Data());
322
323
1
  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
324
1
  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
325
1
  fields[2] = rusage.ru_maxrss;
326
1
  fields[3] = rusage.ru_ixrss;
327
1
  fields[4] = rusage.ru_idrss;
328
1
  fields[5] = rusage.ru_isrss;
329
1
  fields[6] = rusage.ru_minflt;
330
1
  fields[7] = rusage.ru_majflt;
331
1
  fields[8] = rusage.ru_nswap;
332
1
  fields[9] = rusage.ru_inblock;
333
1
  fields[10] = rusage.ru_oublock;
334
1
  fields[11] = rusage.ru_msgsnd;
335
1
  fields[12] = rusage.ru_msgrcv;
336
1
  fields[13] = rusage.ru_nsignals;
337
1
  fields[14] = rusage.ru_nvcsw;
338
1
  fields[15] = rusage.ru_nivcsw;
339
}
340
341
#ifdef __POSIX__
342
3
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
343
3
  Environment* env = Environment::GetCurrent(args);
344
345
3
  if (args.Length() != 1) {
346
    return env->ThrowError("Invalid number of arguments.");
347
  }
348
349
6
  CHECK(args[0]->IsNumber());
350
9
  pid_t pid = args[0].As<Integer>()->Value();
351
3
  int r = kill(pid, SIGUSR1);
352
353
3
  if (r != 0) {
354
1
    return env->ThrowErrnoException(errno, "kill");
355
  }
356
}
357
#endif  // __POSIX__
358
359
#ifdef _WIN32
360
static int GetDebugSignalHandlerMappingName(DWORD pid,
361
                                            wchar_t* buf,
362
                                            size_t buf_len) {
363
  return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
364
}
365
366
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
367
  Environment* env = Environment::GetCurrent(args);
368
  Isolate* isolate = args.GetIsolate();
369
370
  if (args.Length() != 1) {
371
    env->ThrowError("Invalid number of arguments.");
372
    return;
373
  }
374
375
  HANDLE process = nullptr;
376
  HANDLE thread = nullptr;
377
  HANDLE mapping = nullptr;
378
  wchar_t mapping_name[32];
379
  LPTHREAD_START_ROUTINE* handler = nullptr;
380
  DWORD pid = 0;
381
382
  auto cleanup = OnScopeLeave([&]() {
383
    if (process != nullptr) CloseHandle(process);
384
    if (thread != nullptr) CloseHandle(thread);
385
    if (handler != nullptr) UnmapViewOfFile(handler);
386
    if (mapping != nullptr) CloseHandle(mapping);
387
  });
388
389
  CHECK(args[0]->IsNumber());
390
  pid = args[0].As<Integer>()->Value();
391
392
  process =
393
      OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
394
                      PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
395
                  FALSE,
396
                  pid);
397
  if (process == nullptr) {
398
    isolate->ThrowException(
399
        WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
400
    return;
401
  }
402
403
  if (GetDebugSignalHandlerMappingName(
404
          pid, mapping_name, arraysize(mapping_name)) < 0) {
405
    env->ThrowErrnoException(errno, "sprintf");
406
    return;
407
  }
408
409
  mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
410
  if (mapping == nullptr) {
411
    isolate->ThrowException(
412
        WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
413
    return;
414
  }
415
416
  handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
417
      MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
418
  if (handler == nullptr || *handler == nullptr) {
419
    isolate->ThrowException(
420
        WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
421
    return;
422
  }
423
424
  thread =
425
      CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
426
  if (thread == nullptr) {
427
    isolate->ThrowException(
428
        WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
429
    return;
430
  }
431
432
  // Wait for the thread to terminate
433
  if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
434
    isolate->ThrowException(
435
        WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
436
    return;
437
  }
438
}
439
#endif  // _WIN32
440
441
5
static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
442
#if HAVE_INSPECTOR
443
5
  Environment* env = Environment::GetCurrent(args);
444
5
  if (env->inspector_agent()->IsListening()) {
445
4
    env->inspector_agent()->Stop();
446
  }
447
#endif
448
5
}
449
450
259
static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
451
259
  Environment* env = Environment::GetCurrent(args);
452
259
  RunAtExit(env);
453
1036
  int code = args[0]->Int32Value(env->context()).FromMaybe(0);
454
259
  env->Exit(code);
455
42
}
456
457
4594
static void InitializeProcessMethods(Local<Object> target,
458
                                     Local<Value> unused,
459
                                     Local<Context> context,
460
                                     void* priv) {
461
4594
  Environment* env = Environment::GetCurrent(context);
462
463
  // define various internal methods
464
4594
  if (env->owns_process_state()) {
465
4292
    env->SetMethod(target, "_debugProcess", DebugProcess);
466
4292
    env->SetMethod(target, "_debugEnd", DebugEnd);
467
4292
    env->SetMethod(target, "abort", Abort);
468
4292
    env->SetMethod(target, "causeSegfault", CauseSegfault);
469
4292
    env->SetMethod(target, "chdir", Chdir);
470
  }
471
472
  env->SetMethod(
473
4594
      target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
474
4594
  env->SetMethod(target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
475
476
4594
  env->SetMethod(target, "umask", Umask);
477
4594
  env->SetMethod(target, "_rawDebug", RawDebug);
478
4594
  env->SetMethod(target, "memoryUsage", MemoryUsage);
479
4594
  env->SetMethod(target, "cpuUsage", CPUUsage);
480
4594
  env->SetMethod(target, "hrtime", Hrtime);
481
4594
  env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
482
4594
  env->SetMethod(target, "resourceUsage", ResourceUsage);
483
484
4594
  env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
485
4594
  env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
486
4594
  env->SetMethod(target, "_kill", Kill);
487
488
4594
  env->SetMethodNoSideEffect(target, "cwd", Cwd);
489
4594
  env->SetMethod(target, "dlopen", binding::DLOpen);
490
4594
  env->SetMethod(target, "reallyExit", ReallyExit);
491
4594
  env->SetMethodNoSideEffect(target, "uptime", Uptime);
492
4594
  env->SetMethod(target, "patchProcessObject", PatchProcessObject);
493
4594
}
494
495
}  // namespace node
496
497

17303
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
498
                                   node::InitializeProcessMethods)