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