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