• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::FunctionCallbackInfo;
40 using v8::HeapStatistics;
41 using v8::Integer;
42 using v8::Isolate;
43 using v8::Local;
44 using v8::NewStringType;
45 using v8::Number;
46 using v8::Object;
47 using v8::String;
48 using v8::Uint32;
49 using v8::Uint32Array;
50 using v8::Value;
51 
52 namespace per_process {
53 Mutex umask_mutex;
54 }   // namespace per_process
55 
56 // Microseconds in a second, as a float, used in CPUUsage() below
57 #define MICROS_PER_SEC 1e6
58 // used in Hrtime() and Uptime() below
59 #define NANOS_PER_SEC 1000000000
60 
Abort(const FunctionCallbackInfo<Value> & args)61 static void Abort(const FunctionCallbackInfo<Value>& args) {
62   Abort();
63 }
64 
Chdir(const FunctionCallbackInfo<Value> & args)65 static void Chdir(const FunctionCallbackInfo<Value>& args) {
66   Environment* env = Environment::GetCurrent(args);
67   CHECK(env->owns_process_state());
68 
69   CHECK_EQ(args.Length(), 1);
70   CHECK(args[0]->IsString());
71   Utf8Value path(env->isolate(), args[0]);
72   int err = uv_chdir(*path);
73   if (err) {
74     // Also include the original working directory, since that will usually
75     // be helpful information when debugging a `chdir()` failure.
76     char buf[PATH_MAX_BYTES];
77     size_t cwd_len = sizeof(buf);
78     uv_cwd(buf, &cwd_len);
79     return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
80   }
81 }
82 
83 // CPUUsage use libuv's uv_getrusage() this-process resource usage accessor,
84 // to access ru_utime (user CPU time used) and ru_stime (system CPU time used),
85 // which are uv_timeval_t structs (long tv_sec, long tv_usec).
86 // Returns those values as Float64 microseconds in the elements of the array
87 // passed to the function.
CPUUsage(const FunctionCallbackInfo<Value> & args)88 static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
89   uv_rusage_t rusage;
90 
91   // Call libuv to get the values we'll return.
92   int err = uv_getrusage(&rusage);
93   if (err) {
94     // On error, return the strerror version of the error code.
95     Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err));
96     return args.GetReturnValue().Set(errmsg);
97   }
98 
99   // Get the double array pointer from the Float64Array argument.
100   CHECK(args[0]->IsFloat64Array());
101   Local<Float64Array> array = args[0].As<Float64Array>();
102   CHECK_EQ(array->Length(), 2);
103   Local<ArrayBuffer> ab = array->Buffer();
104   double* fields = static_cast<double*>(ab->GetContents().Data());
105 
106   // Set the Float64Array elements to be user / system values in microseconds.
107   fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
108   fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
109 }
110 
Cwd(const FunctionCallbackInfo<Value> & args)111 static void Cwd(const FunctionCallbackInfo<Value>& args) {
112   Environment* env = Environment::GetCurrent(args);
113   CHECK(env->has_run_bootstrapping_code());
114   char buf[PATH_MAX_BYTES];
115   size_t cwd_len = sizeof(buf);
116   int err = uv_cwd(buf, &cwd_len);
117   if (err)
118     return env->ThrowUVException(err, "uv_cwd");
119 
120   Local<String> cwd = String::NewFromUtf8(env->isolate(),
121                                           buf,
122                                           NewStringType::kNormal,
123                                           cwd_len).ToLocalChecked();
124   args.GetReturnValue().Set(cwd);
125 }
126 
127 
128 // Hrtime exposes libuv's uv_hrtime() high-resolution timer.
129 
130 // This is the legacy version of hrtime before BigInt was introduced in
131 // JavaScript.
132 // The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
133 // so this function instead fills in an Uint32Array with 3 entries,
134 // to avoid any integer overflow possibility.
135 // The first two entries contain the second part of the value
136 // broken into the upper/lower 32 bits to be converted back in JS,
137 // because there is no Uint64Array in JS.
138 // The third entry contains the remaining nanosecond part of the value.
Hrtime(const FunctionCallbackInfo<Value> & args)139 static void Hrtime(const FunctionCallbackInfo<Value>& args) {
140   uint64_t t = uv_hrtime();
141 
142   Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
143   uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
144 
145   fields[0] = (t / NANOS_PER_SEC) >> 32;
146   fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
147   fields[2] = t % NANOS_PER_SEC;
148 }
149 
HrtimeBigInt(const FunctionCallbackInfo<Value> & args)150 static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
151   Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
152   uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
153   fields[0] = uv_hrtime();
154 }
155 
Kill(const FunctionCallbackInfo<Value> & args)156 static void Kill(const FunctionCallbackInfo<Value>& args) {
157   Environment* env = Environment::GetCurrent(args);
158   Local<Context> context = env->context();
159 
160   if (args.Length() < 2) {
161     THROW_ERR_MISSING_ARGS(env, "Bad argument.");
162   }
163 
164   int pid;
165   if (!args[0]->Int32Value(context).To(&pid)) return;
166   int sig;
167   if (!args[1]->Int32Value(context).To(&sig)) return;
168 
169   uv_pid_t own_pid = uv_os_getpid();
170   if (sig > 0 &&
171       (pid == 0 || pid == -1 || pid == own_pid || pid == -own_pid) &&
172       !HasSignalJSHandler(sig)) {
173     // This is most likely going to terminate this process.
174     // It's not an exact method but it might be close enough.
175     RunAtExit(env);
176   }
177 
178   int err = uv_kill(pid, sig);
179   args.GetReturnValue().Set(err);
180 }
181 
MemoryUsage(const FunctionCallbackInfo<Value> & args)182 static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
183   Environment* env = Environment::GetCurrent(args);
184 
185   size_t rss;
186   int err = uv_resident_set_memory(&rss);
187   if (err)
188     return env->ThrowUVException(err, "uv_resident_set_memory");
189 
190   Isolate* isolate = env->isolate();
191   // V8 memory usage
192   HeapStatistics v8_heap_stats;
193   isolate->GetHeapStatistics(&v8_heap_stats);
194 
195   NodeArrayBufferAllocator* array_buffer_allocator =
196       env->isolate_data()->node_allocator();
197 
198   // Get the double array pointer from the Float64Array argument.
199   CHECK(args[0]->IsFloat64Array());
200   Local<Float64Array> array = args[0].As<Float64Array>();
201   CHECK_EQ(array->Length(), 5);
202   Local<ArrayBuffer> ab = array->Buffer();
203   double* fields = static_cast<double*>(ab->GetContents().Data());
204 
205   fields[0] = rss;
206   fields[1] = v8_heap_stats.total_heap_size();
207   fields[2] = v8_heap_stats.used_heap_size();
208   fields[3] = v8_heap_stats.external_memory();
209   fields[4] = array_buffer_allocator == nullptr ?
210       0 : array_buffer_allocator->total_mem_usage();
211 }
212 
RawDebug(const FunctionCallbackInfo<Value> & args)213 void RawDebug(const FunctionCallbackInfo<Value>& args) {
214   CHECK(args.Length() == 1 && args[0]->IsString() &&
215         "must be called with a single string");
216   Utf8Value message(args.GetIsolate(), args[0]);
217   FPrintF(stderr, "%s\n", message);
218   fflush(stderr);
219 }
220 
StartProfilerIdleNotifier(const FunctionCallbackInfo<Value> & args)221 static void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
222   Environment* env = Environment::GetCurrent(args);
223   env->StartProfilerIdleNotifier();
224 }
225 
StopProfilerIdleNotifier(const FunctionCallbackInfo<Value> & args)226 static void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
227   Environment* env = Environment::GetCurrent(args);
228   env->StopProfilerIdleNotifier();
229 }
230 
Umask(const FunctionCallbackInfo<Value> & args)231 static void Umask(const FunctionCallbackInfo<Value>& args) {
232   Environment* env = Environment::GetCurrent(args);
233   CHECK(env->has_run_bootstrapping_code());
234   CHECK_EQ(args.Length(), 1);
235   CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
236   Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
237 
238   uint32_t old;
239   if (args[0]->IsUndefined()) {
240     old = umask(0);
241     umask(static_cast<mode_t>(old));
242   } else {
243     int oct = args[0].As<Uint32>()->Value();
244     old = umask(static_cast<mode_t>(oct));
245   }
246 
247   args.GetReturnValue().Set(old);
248 }
249 
Uptime(const FunctionCallbackInfo<Value> & args)250 static void Uptime(const FunctionCallbackInfo<Value>& args) {
251   Environment* env = Environment::GetCurrent(args);
252 
253   uv_update_time(env->event_loop());
254   double uptime =
255       static_cast<double>(uv_hrtime() - per_process::node_start_time);
256   Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC);
257   args.GetReturnValue().Set(result);
258 }
259 
GetActiveRequests(const FunctionCallbackInfo<Value> & args)260 static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
261   Environment* env = Environment::GetCurrent(args);
262 
263   std::vector<Local<Value>> request_v;
264   for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
265     AsyncWrap* w = req_wrap->GetAsyncWrap();
266     if (w->persistent().IsEmpty())
267       continue;
268     request_v.emplace_back(w->GetOwner());
269   }
270 
271   args.GetReturnValue().Set(
272       Array::New(env->isolate(), request_v.data(), request_v.size()));
273 }
274 
275 // Non-static, friend of HandleWrap. Could have been a HandleWrap method but
276 // implemented here for consistency with GetActiveRequests().
GetActiveHandles(const FunctionCallbackInfo<Value> & args)277 void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
278   Environment* env = Environment::GetCurrent(args);
279 
280   std::vector<Local<Value>> handle_v;
281   for (auto w : *env->handle_wrap_queue()) {
282     if (!HandleWrap::HasRef(w))
283       continue;
284     handle_v.emplace_back(w->GetOwner());
285   }
286   args.GetReturnValue().Set(
287       Array::New(env->isolate(), handle_v.data(), handle_v.size()));
288 }
289 
ResourceUsage(const FunctionCallbackInfo<Value> & args)290 static void ResourceUsage(const FunctionCallbackInfo<Value>& args) {
291   Environment* env = Environment::GetCurrent(args);
292 
293   uv_rusage_t rusage;
294   int err = uv_getrusage(&rusage);
295   if (err)
296     return env->ThrowUVException(err, "uv_getrusage");
297 
298   CHECK(args[0]->IsFloat64Array());
299   Local<Float64Array> array = args[0].As<Float64Array>();
300   CHECK_EQ(array->Length(), 16);
301   Local<ArrayBuffer> ab = array->Buffer();
302   double* fields = static_cast<double*>(ab->GetContents().Data());
303 
304   fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
305   fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
306   fields[2] = rusage.ru_maxrss;
307   fields[3] = rusage.ru_ixrss;
308   fields[4] = rusage.ru_idrss;
309   fields[5] = rusage.ru_isrss;
310   fields[6] = rusage.ru_minflt;
311   fields[7] = rusage.ru_majflt;
312   fields[8] = rusage.ru_nswap;
313   fields[9] = rusage.ru_inblock;
314   fields[10] = rusage.ru_oublock;
315   fields[11] = rusage.ru_msgsnd;
316   fields[12] = rusage.ru_msgrcv;
317   fields[13] = rusage.ru_nsignals;
318   fields[14] = rusage.ru_nvcsw;
319   fields[15] = rusage.ru_nivcsw;
320 }
321 
322 #ifdef __POSIX__
DebugProcess(const FunctionCallbackInfo<Value> & args)323 static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
324   Environment* env = Environment::GetCurrent(args);
325 
326   if (args.Length() < 1) {
327     return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments.");
328   }
329 
330   CHECK(args[0]->IsNumber());
331   pid_t pid = args[0].As<Integer>()->Value();
332   int r = kill(pid, SIGUSR1);
333 
334   if (r != 0) {
335     return env->ThrowErrnoException(errno, "kill");
336   }
337 }
338 #endif  // __POSIX__
339 
340 #ifdef _WIN32
GetDebugSignalHandlerMappingName(DWORD pid,wchar_t * buf,size_t buf_len)341 static int GetDebugSignalHandlerMappingName(DWORD pid,
342                                             wchar_t* buf,
343                                             size_t buf_len) {
344   return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
345 }
346 
DebugProcess(const FunctionCallbackInfo<Value> & args)347 static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
348   Environment* env = Environment::GetCurrent(args);
349   Isolate* isolate = args.GetIsolate();
350 
351   if (args.Length() < 1) {
352     return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments.");
353   }
354 
355   HANDLE process = nullptr;
356   HANDLE thread = nullptr;
357   HANDLE mapping = nullptr;
358   wchar_t mapping_name[32];
359   LPTHREAD_START_ROUTINE* handler = nullptr;
360   DWORD pid = 0;
361 
362   auto cleanup = OnScopeLeave([&]() {
363     if (process != nullptr) CloseHandle(process);
364     if (thread != nullptr) CloseHandle(thread);
365     if (handler != nullptr) UnmapViewOfFile(handler);
366     if (mapping != nullptr) CloseHandle(mapping);
367   });
368 
369   CHECK(args[0]->IsNumber());
370   pid = args[0].As<Integer>()->Value();
371 
372   process =
373       OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
374                       PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
375                   FALSE,
376                   pid);
377   if (process == nullptr) {
378     isolate->ThrowException(
379         WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
380     return;
381   }
382 
383   if (GetDebugSignalHandlerMappingName(
384           pid, mapping_name, arraysize(mapping_name)) < 0) {
385     env->ThrowErrnoException(errno, "sprintf");
386     return;
387   }
388 
389   mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
390   if (mapping == nullptr) {
391     isolate->ThrowException(
392         WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
393     return;
394   }
395 
396   handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
397       MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
398   if (handler == nullptr || *handler == nullptr) {
399     isolate->ThrowException(
400         WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
401     return;
402   }
403 
404   thread =
405       CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
406   if (thread == nullptr) {
407     isolate->ThrowException(
408         WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
409     return;
410   }
411 
412   // Wait for the thread to terminate
413   if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
414     isolate->ThrowException(
415         WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
416     return;
417   }
418 }
419 #endif  // _WIN32
420 
DebugEnd(const FunctionCallbackInfo<Value> & args)421 static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
422 #if HAVE_INSPECTOR
423   Environment* env = Environment::GetCurrent(args);
424   if (env->inspector_agent()->IsListening()) {
425     env->inspector_agent()->Stop();
426   }
427 #endif
428 }
429 
ReallyExit(const FunctionCallbackInfo<Value> & args)430 static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
431   Environment* env = Environment::GetCurrent(args);
432   RunAtExit(env);
433   int code = args[0]->Int32Value(env->context()).FromMaybe(0);
434   env->Exit(code);
435 }
436 
InitializeProcessMethods(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)437 static void InitializeProcessMethods(Local<Object> target,
438                                      Local<Value> unused,
439                                      Local<Context> context,
440                                      void* priv) {
441   Environment* env = Environment::GetCurrent(context);
442 
443   // define various internal methods
444   if (env->owns_process_state()) {
445     env->SetMethod(target, "_debugProcess", DebugProcess);
446     env->SetMethod(target, "_debugEnd", DebugEnd);
447     env->SetMethod(target, "abort", Abort);
448     env->SetMethod(target, "chdir", Chdir);
449   }
450 
451   env->SetMethod(
452       target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
453   env->SetMethod(target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
454 
455   env->SetMethod(target, "umask", Umask);
456   env->SetMethod(target, "_rawDebug", RawDebug);
457   env->SetMethod(target, "memoryUsage", MemoryUsage);
458   env->SetMethod(target, "cpuUsage", CPUUsage);
459   env->SetMethod(target, "hrtime", Hrtime);
460   env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
461   env->SetMethod(target, "resourceUsage", ResourceUsage);
462 
463   env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
464   env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
465   env->SetMethod(target, "_kill", Kill);
466 
467   env->SetMethodNoSideEffect(target, "cwd", Cwd);
468   env->SetMethod(target, "dlopen", binding::DLOpen);
469   env->SetMethod(target, "reallyExit", ReallyExit);
470   env->SetMethodNoSideEffect(target, "uptime", Uptime);
471   env->SetMethod(target, "patchProcessObject", PatchProcessObject);
472 }
473 
474 }  // namespace node
475 
476 NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
477                                    node::InitializeProcessMethods)
478