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