/src/node/src/node_process_methods.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "async_wrap-inl.h" |
2 | | #include "base_object-inl.h" |
3 | | #include "debug_utils-inl.h" |
4 | | #include "env-inl.h" |
5 | | #include "memory_tracker-inl.h" |
6 | | #include "node.h" |
7 | | #include "node_dotenv.h" |
8 | | #include "node_errors.h" |
9 | | #include "node_external_reference.h" |
10 | | #include "node_internals.h" |
11 | | #include "node_process-inl.h" |
12 | | #include "util-inl.h" |
13 | | #include "uv.h" |
14 | | #include "v8-fast-api-calls.h" |
15 | | #include "v8.h" |
16 | | |
17 | | #include <vector> |
18 | | |
19 | | #if HAVE_INSPECTOR |
20 | | #include "inspector_io.h" |
21 | | #endif |
22 | | |
23 | | #include <climits> // PATH_MAX |
24 | | #include <cstdio> |
25 | | |
26 | | #if defined(_MSC_VER) |
27 | | #include <direct.h> |
28 | | #include <io.h> |
29 | | #define umask _umask |
30 | | typedef int mode_t; |
31 | | #else |
32 | | #include <pthread.h> |
33 | | #include <sys/resource.h> // getrlimit, setrlimit |
34 | | #include <termios.h> // tcgetattr, tcsetattr |
35 | | #endif |
36 | | |
37 | | namespace node { |
38 | | |
39 | | using v8::Array; |
40 | | using v8::ArrayBuffer; |
41 | | using v8::CFunction; |
42 | | using v8::Context; |
43 | | using v8::Float64Array; |
44 | | using v8::Function; |
45 | | using v8::FunctionCallbackInfo; |
46 | | using v8::HeapStatistics; |
47 | | using v8::Integer; |
48 | | using v8::Isolate; |
49 | | using v8::Local; |
50 | | using v8::Maybe; |
51 | | using v8::NewStringType; |
52 | | using v8::Number; |
53 | | using v8::Object; |
54 | | using v8::ObjectTemplate; |
55 | | using v8::String; |
56 | | using v8::Uint32; |
57 | | using v8::Value; |
58 | | |
59 | | namespace per_process { |
60 | | Mutex umask_mutex; |
61 | | } // namespace per_process |
62 | | |
63 | | // Microseconds in a second, as a float, used in CPUUsage() below |
64 | 0 | #define MICROS_PER_SEC 1e6 |
65 | | // used in Hrtime() and Uptime() below |
66 | 0 | #define NANOS_PER_SEC 1000000000 |
67 | | |
68 | 0 | static void Abort(const FunctionCallbackInfo<Value>& args) { |
69 | 0 | ABORT(); |
70 | 0 | } |
71 | | |
72 | | // For internal testing only, not exposed to userland. |
73 | 0 | static void CauseSegfault(const FunctionCallbackInfo<Value>& args) { |
74 | | // This should crash hard all platforms. |
75 | 0 | volatile void** d = static_cast<volatile void**>(nullptr); |
76 | 0 | *d = nullptr; |
77 | 0 | } |
78 | | |
79 | 0 | static void Chdir(const FunctionCallbackInfo<Value>& args) { |
80 | 0 | Environment* env = Environment::GetCurrent(args); |
81 | 0 | CHECK(env->owns_process_state()); |
82 | | |
83 | 0 | CHECK_EQ(args.Length(), 1); |
84 | 0 | CHECK(args[0]->IsString()); |
85 | 0 | Utf8Value path(env->isolate(), args[0]); |
86 | 0 | int err = uv_chdir(*path); |
87 | 0 | if (err) { |
88 | | // Also include the original working directory, since that will usually |
89 | | // be helpful information when debugging a `chdir()` failure. |
90 | 0 | char buf[PATH_MAX_BYTES]; |
91 | 0 | size_t cwd_len = sizeof(buf); |
92 | 0 | uv_cwd(buf, &cwd_len); |
93 | 0 | return env->ThrowUVException(err, "chdir", nullptr, buf, *path); |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | | inline Local<ArrayBuffer> get_fields_array_buffer( |
98 | | const FunctionCallbackInfo<Value>& args, |
99 | | size_t index, |
100 | 0 | size_t array_length) { |
101 | 0 | CHECK(args[index]->IsFloat64Array()); |
102 | 0 | Local<Float64Array> arr = args[index].As<Float64Array>(); |
103 | 0 | CHECK_EQ(arr->Length(), array_length); |
104 | 0 | return arr->Buffer(); |
105 | 0 | } |
106 | | |
107 | | // CPUUsage use libuv's uv_getrusage() this-process resource usage accessor, |
108 | | // to access ru_utime (user CPU time used) and ru_stime (system CPU time used), |
109 | | // which are uv_timeval_t structs (long tv_sec, long tv_usec). |
110 | | // Returns those values as Float64 microseconds in the elements of the array |
111 | | // passed to the function. |
112 | 0 | static void CPUUsage(const FunctionCallbackInfo<Value>& args) { |
113 | 0 | Environment* env = Environment::GetCurrent(args); |
114 | 0 | uv_rusage_t rusage; |
115 | | |
116 | | // Call libuv to get the values we'll return. |
117 | 0 | int err = uv_getrusage(&rusage); |
118 | 0 | if (err) |
119 | 0 | return env->ThrowUVException(err, "uv_getrusage"); |
120 | | |
121 | | // Get the double array pointer from the Float64Array argument. |
122 | 0 | Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 2); |
123 | 0 | double* fields = static_cast<double*>(ab->Data()); |
124 | | |
125 | | // Set the Float64Array elements to be user / system values in microseconds. |
126 | 0 | fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec; |
127 | 0 | fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec; |
128 | 0 | } |
129 | | |
130 | 1.33k | static void Cwd(const FunctionCallbackInfo<Value>& args) { |
131 | 1.33k | Environment* env = Environment::GetCurrent(args); |
132 | 1.33k | CHECK(env->has_run_bootstrapping_code()); |
133 | 1.33k | char buf[PATH_MAX_BYTES]; |
134 | 1.33k | size_t cwd_len = sizeof(buf); |
135 | 1.33k | int err = uv_cwd(buf, &cwd_len); |
136 | 1.33k | if (err) |
137 | 0 | return env->ThrowUVException(err, "uv_cwd"); |
138 | | |
139 | 1.33k | Local<String> cwd = String::NewFromUtf8(env->isolate(), |
140 | 1.33k | buf, |
141 | 1.33k | NewStringType::kNormal, |
142 | 1.33k | cwd_len).ToLocalChecked(); |
143 | 1.33k | args.GetReturnValue().Set(cwd); |
144 | 1.33k | } |
145 | | |
146 | 0 | static void Kill(const FunctionCallbackInfo<Value>& args) { |
147 | 0 | Environment* env = Environment::GetCurrent(args); |
148 | 0 | Local<Context> context = env->context(); |
149 | |
|
150 | 0 | if (args.Length() < 2) { |
151 | 0 | THROW_ERR_MISSING_ARGS(env, "Bad argument."); |
152 | 0 | } |
153 | |
|
154 | 0 | int pid; |
155 | 0 | if (!args[0]->Int32Value(context).To(&pid)) return; |
156 | 0 | int sig; |
157 | 0 | if (!args[1]->Int32Value(context).To(&sig)) return; |
158 | | |
159 | 0 | uv_pid_t own_pid = uv_os_getpid(); |
160 | 0 | if (sig > 0 && |
161 | 0 | (pid == 0 || pid == -1 || pid == own_pid || pid == -own_pid) && |
162 | 0 | !HasSignalJSHandler(sig)) { |
163 | | // This is most likely going to terminate this process. |
164 | | // It's not an exact method but it might be close enough. |
165 | 0 | RunAtExit(env); |
166 | 0 | } |
167 | |
|
168 | 0 | int err = uv_kill(pid, sig); |
169 | 0 | args.GetReturnValue().Set(err); |
170 | 0 | } |
171 | | |
172 | 0 | static void Rss(const FunctionCallbackInfo<Value>& args) { |
173 | 0 | Environment* env = Environment::GetCurrent(args); |
174 | |
|
175 | 0 | size_t rss; |
176 | 0 | int err = uv_resident_set_memory(&rss); |
177 | 0 | if (err) |
178 | 0 | return env->ThrowUVException(err, "uv_resident_set_memory"); |
179 | | |
180 | 0 | args.GetReturnValue().Set(static_cast<double>(rss)); |
181 | 0 | } |
182 | | |
183 | 0 | static void MemoryUsage(const FunctionCallbackInfo<Value>& args) { |
184 | 0 | Environment* env = Environment::GetCurrent(args); |
185 | |
|
186 | 0 | Isolate* isolate = env->isolate(); |
187 | | // V8 memory usage |
188 | 0 | HeapStatistics v8_heap_stats; |
189 | 0 | isolate->GetHeapStatistics(&v8_heap_stats); |
190 | |
|
191 | 0 | NodeArrayBufferAllocator* array_buffer_allocator = |
192 | 0 | env->isolate_data()->node_allocator(); |
193 | | |
194 | | // Get the double array pointer from the Float64Array argument. |
195 | 0 | Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 5); |
196 | 0 | double* fields = static_cast<double*>(ab->Data()); |
197 | |
|
198 | 0 | size_t rss; |
199 | 0 | int err = uv_resident_set_memory(&rss); |
200 | 0 | if (err) |
201 | 0 | return env->ThrowUVException(err, "uv_resident_set_memory"); |
202 | | |
203 | 0 | fields[0] = static_cast<double>(rss); |
204 | 0 | fields[1] = static_cast<double>(v8_heap_stats.total_heap_size()); |
205 | 0 | fields[2] = static_cast<double>(v8_heap_stats.used_heap_size()); |
206 | 0 | fields[3] = static_cast<double>(v8_heap_stats.external_memory()); |
207 | 0 | fields[4] = |
208 | 0 | array_buffer_allocator == nullptr |
209 | 0 | ? 0 |
210 | 0 | : static_cast<double>(array_buffer_allocator->total_mem_usage()); |
211 | 0 | } |
212 | | |
213 | 0 | static void GetConstrainedMemory(const FunctionCallbackInfo<Value>& args) { |
214 | 0 | uint64_t value = uv_get_constrained_memory(); |
215 | 0 | args.GetReturnValue().Set(static_cast<double>(value)); |
216 | 0 | } |
217 | | |
218 | 0 | static void GetAvailableMemory(const FunctionCallbackInfo<Value>& args) { |
219 | 0 | uint64_t value = uv_get_available_memory(); |
220 | 0 | args.GetReturnValue().Set(static_cast<double>(value)); |
221 | 0 | } |
222 | | |
223 | 0 | void RawDebug(const FunctionCallbackInfo<Value>& args) { |
224 | 0 | CHECK(args.Length() == 1 && args[0]->IsString() && |
225 | 0 | "must be called with a single string"); |
226 | 0 | Utf8Value message(args.GetIsolate(), args[0]); |
227 | 0 | FPrintF(stderr, "%s\n", message); |
228 | 0 | fflush(stderr); |
229 | 0 | } |
230 | | |
231 | 0 | static void Umask(const FunctionCallbackInfo<Value>& args) { |
232 | 0 | Environment* env = Environment::GetCurrent(args); |
233 | 0 | CHECK(env->has_run_bootstrapping_code()); |
234 | 0 | CHECK_EQ(args.Length(), 1); |
235 | 0 | CHECK(args[0]->IsUndefined() || args[0]->IsUint32()); |
236 | 0 | Mutex::ScopedLock scoped_lock(per_process::umask_mutex); |
237 | |
|
238 | 0 | uint32_t old; |
239 | 0 | if (args[0]->IsUndefined()) { |
240 | 0 | old = umask(0); |
241 | 0 | umask(static_cast<mode_t>(old)); |
242 | 0 | } else { |
243 | 0 | int oct = args[0].As<Uint32>()->Value(); |
244 | 0 | old = umask(static_cast<mode_t>(oct)); |
245 | 0 | } |
246 | |
|
247 | 0 | args.GetReturnValue().Set(old); |
248 | 0 | } |
249 | | |
250 | 0 | static void Uptime(const FunctionCallbackInfo<Value>& args) { |
251 | 0 | Environment* env = Environment::GetCurrent(args); |
252 | |
|
253 | 0 | uv_update_time(env->event_loop()); |
254 | 0 | double uptime = |
255 | 0 | static_cast<double>(uv_hrtime() - per_process::node_start_time); |
256 | 0 | Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC); |
257 | 0 | args.GetReturnValue().Set(result); |
258 | 0 | } |
259 | | |
260 | 0 | static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) { |
261 | 0 | Environment* env = Environment::GetCurrent(args); |
262 | |
|
263 | 0 | std::vector<Local<Value>> request_v; |
264 | 0 | for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) { |
265 | 0 | AsyncWrap* w = req_wrap->GetAsyncWrap(); |
266 | 0 | if (w->persistent().IsEmpty()) |
267 | 0 | continue; |
268 | 0 | request_v.emplace_back(w->GetOwner()); |
269 | 0 | } |
270 | |
|
271 | 0 | args.GetReturnValue().Set( |
272 | 0 | Array::New(env->isolate(), request_v.data(), request_v.size())); |
273 | 0 | } |
274 | | |
275 | | // Non-static, friend of HandleWrap. Could have been a HandleWrap method but |
276 | | // implemented here for consistency with GetActiveRequests(). |
277 | 0 | void GetActiveHandles(const FunctionCallbackInfo<Value>& args) { |
278 | 0 | Environment* env = Environment::GetCurrent(args); |
279 | |
|
280 | 0 | std::vector<Local<Value>> handle_v; |
281 | 0 | for (auto w : *env->handle_wrap_queue()) { |
282 | 0 | if (!HandleWrap::HasRef(w)) |
283 | 0 | continue; |
284 | 0 | handle_v.emplace_back(w->GetOwner()); |
285 | 0 | } |
286 | 0 | args.GetReturnValue().Set( |
287 | 0 | Array::New(env->isolate(), handle_v.data(), handle_v.size())); |
288 | 0 | } |
289 | | |
290 | 0 | static void GetActiveResourcesInfo(const FunctionCallbackInfo<Value>& args) { |
291 | 0 | Environment* env = Environment::GetCurrent(args); |
292 | 0 | std::vector<Local<Value>> resources_info; |
293 | | |
294 | | // Active requests |
295 | 0 | for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) { |
296 | 0 | AsyncWrap* w = req_wrap->GetAsyncWrap(); |
297 | 0 | if (w->persistent().IsEmpty()) continue; |
298 | 0 | resources_info.emplace_back( |
299 | 0 | OneByteString(env->isolate(), w->MemoryInfoName())); |
300 | 0 | } |
301 | | |
302 | | // Active handles |
303 | 0 | for (HandleWrap* w : *env->handle_wrap_queue()) { |
304 | 0 | if (w->persistent().IsEmpty() || !HandleWrap::HasRef(w)) continue; |
305 | 0 | resources_info.emplace_back( |
306 | 0 | OneByteString(env->isolate(), w->MemoryInfoName())); |
307 | 0 | } |
308 | | |
309 | | // Active timeouts |
310 | 0 | resources_info.insert(resources_info.end(), |
311 | 0 | env->timeout_info()[0], |
312 | 0 | OneByteString(env->isolate(), "Timeout")); |
313 | | |
314 | | // Active immediates |
315 | 0 | resources_info.insert(resources_info.end(), |
316 | 0 | env->immediate_info()->ref_count(), |
317 | 0 | OneByteString(env->isolate(), "Immediate")); |
318 | |
|
319 | 0 | args.GetReturnValue().Set( |
320 | 0 | Array::New(env->isolate(), resources_info.data(), resources_info.size())); |
321 | 0 | } |
322 | | |
323 | 0 | static void ResourceUsage(const FunctionCallbackInfo<Value>& args) { |
324 | 0 | Environment* env = Environment::GetCurrent(args); |
325 | |
|
326 | 0 | uv_rusage_t rusage; |
327 | 0 | int err = uv_getrusage(&rusage); |
328 | 0 | if (err) |
329 | 0 | return env->ThrowUVException(err, "uv_getrusage"); |
330 | | |
331 | 0 | Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 16); |
332 | 0 | double* fields = static_cast<double*>(ab->Data()); |
333 | |
|
334 | 0 | fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec; |
335 | 0 | fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec; |
336 | 0 | fields[2] = static_cast<double>(rusage.ru_maxrss); |
337 | 0 | fields[3] = static_cast<double>(rusage.ru_ixrss); |
338 | 0 | fields[4] = static_cast<double>(rusage.ru_idrss); |
339 | 0 | fields[5] = static_cast<double>(rusage.ru_isrss); |
340 | 0 | fields[6] = static_cast<double>(rusage.ru_minflt); |
341 | 0 | fields[7] = static_cast<double>(rusage.ru_majflt); |
342 | 0 | fields[8] = static_cast<double>(rusage.ru_nswap); |
343 | 0 | fields[9] = static_cast<double>(rusage.ru_inblock); |
344 | 0 | fields[10] = static_cast<double>(rusage.ru_oublock); |
345 | 0 | fields[11] = static_cast<double>(rusage.ru_msgsnd); |
346 | 0 | fields[12] = static_cast<double>(rusage.ru_msgrcv); |
347 | 0 | fields[13] = static_cast<double>(rusage.ru_nsignals); |
348 | 0 | fields[14] = static_cast<double>(rusage.ru_nvcsw); |
349 | 0 | fields[15] = static_cast<double>(rusage.ru_nivcsw); |
350 | 0 | } |
351 | | |
352 | | #ifdef __POSIX__ |
353 | 0 | static void DebugProcess(const FunctionCallbackInfo<Value>& args) { |
354 | 0 | Environment* env = Environment::GetCurrent(args); |
355 | |
|
356 | 0 | if (args.Length() < 1) { |
357 | 0 | return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments."); |
358 | 0 | } |
359 | | |
360 | 0 | CHECK(args[0]->IsNumber()); |
361 | 0 | pid_t pid = args[0].As<Integer>()->Value(); |
362 | 0 | int r = kill(pid, SIGUSR1); |
363 | |
|
364 | 0 | if (r != 0) { |
365 | 0 | return env->ThrowErrnoException(errno, "kill"); |
366 | 0 | } |
367 | 0 | } |
368 | | #endif // __POSIX__ |
369 | | |
370 | | #ifdef _WIN32 |
371 | | static int GetDebugSignalHandlerMappingName(DWORD pid, |
372 | | wchar_t* buf, |
373 | | size_t buf_len) { |
374 | | return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid); |
375 | | } |
376 | | |
377 | | static void DebugProcess(const FunctionCallbackInfo<Value>& args) { |
378 | | Environment* env = Environment::GetCurrent(args); |
379 | | Isolate* isolate = args.GetIsolate(); |
380 | | |
381 | | if (args.Length() < 1) { |
382 | | return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments."); |
383 | | } |
384 | | |
385 | | HANDLE process = nullptr; |
386 | | HANDLE thread = nullptr; |
387 | | HANDLE mapping = nullptr; |
388 | | wchar_t mapping_name[32]; |
389 | | LPTHREAD_START_ROUTINE* handler = nullptr; |
390 | | DWORD pid = 0; |
391 | | |
392 | | auto cleanup = OnScopeLeave([&]() { |
393 | | if (process != nullptr) CloseHandle(process); |
394 | | if (thread != nullptr) CloseHandle(thread); |
395 | | if (handler != nullptr) UnmapViewOfFile(handler); |
396 | | if (mapping != nullptr) CloseHandle(mapping); |
397 | | }); |
398 | | |
399 | | CHECK(args[0]->IsNumber()); |
400 | | pid = static_cast<DWORD>(args[0].As<Integer>()->Value()); |
401 | | |
402 | | process = |
403 | | OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | |
404 | | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, |
405 | | FALSE, |
406 | | pid); |
407 | | if (process == nullptr) { |
408 | | isolate->ThrowException( |
409 | | WinapiErrnoException(isolate, GetLastError(), "OpenProcess")); |
410 | | return; |
411 | | } |
412 | | |
413 | | if (GetDebugSignalHandlerMappingName( |
414 | | pid, mapping_name, arraysize(mapping_name)) < 0) { |
415 | | env->ThrowErrnoException(errno, "sprintf"); |
416 | | return; |
417 | | } |
418 | | |
419 | | mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name); |
420 | | if (mapping == nullptr) { |
421 | | isolate->ThrowException( |
422 | | WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW")); |
423 | | return; |
424 | | } |
425 | | |
426 | | handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>( |
427 | | MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler)); |
428 | | if (handler == nullptr || *handler == nullptr) { |
429 | | isolate->ThrowException( |
430 | | WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile")); |
431 | | return; |
432 | | } |
433 | | |
434 | | thread = |
435 | | CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr); |
436 | | if (thread == nullptr) { |
437 | | isolate->ThrowException( |
438 | | WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread")); |
439 | | return; |
440 | | } |
441 | | |
442 | | // Wait for the thread to terminate |
443 | | if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) { |
444 | | isolate->ThrowException( |
445 | | WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject")); |
446 | | return; |
447 | | } |
448 | | } |
449 | | #endif // _WIN32 |
450 | | |
451 | 0 | static void DebugEnd(const FunctionCallbackInfo<Value>& args) { |
452 | 0 | #if HAVE_INSPECTOR |
453 | 0 | Environment* env = Environment::GetCurrent(args); |
454 | 0 | if (env->inspector_agent()->IsListening()) { |
455 | 0 | env->inspector_agent()->Stop(); |
456 | 0 | } |
457 | 0 | #endif |
458 | 0 | } |
459 | | |
460 | 0 | static void ReallyExit(const FunctionCallbackInfo<Value>& args) { |
461 | 0 | Environment* env = Environment::GetCurrent(args); |
462 | 0 | RunAtExit(env); |
463 | 0 | ExitCode code = ExitCode::kNoFailure; |
464 | 0 | Maybe<int32_t> code_int = args[0]->Int32Value(env->context()); |
465 | 0 | if (!code_int.IsNothing()) { |
466 | 0 | code = static_cast<ExitCode>(code_int.FromJust()); |
467 | 0 | } |
468 | 0 | env->Exit(code); |
469 | 0 | } |
470 | | |
471 | 0 | static void LoadEnvFile(const v8::FunctionCallbackInfo<v8::Value>& args) { |
472 | 0 | Environment* env = Environment::GetCurrent(args); |
473 | 0 | std::string path = ".env"; |
474 | 0 | if (args.Length() == 1) { |
475 | 0 | Utf8Value path_value(args.GetIsolate(), args[0]); |
476 | 0 | path = path_value.ToString(); |
477 | 0 | } |
478 | |
|
479 | 0 | THROW_IF_INSUFFICIENT_PERMISSIONS( |
480 | 0 | env, permission::PermissionScope::kFileSystemRead, path); |
481 | | |
482 | 0 | Dotenv dotenv{}; |
483 | |
|
484 | 0 | switch (dotenv.ParsePath(path)) { |
485 | 0 | case dotenv.ParseResult::Valid: { |
486 | 0 | dotenv.SetEnvironment(env); |
487 | 0 | break; |
488 | 0 | } |
489 | 0 | case dotenv.ParseResult::InvalidContent: { |
490 | 0 | THROW_ERR_INVALID_ARG_TYPE( |
491 | 0 | env, "Contents of '%s' should be a valid string.", path.c_str()); |
492 | 0 | break; |
493 | 0 | } |
494 | 0 | case dotenv.ParseResult::FileError: { |
495 | 0 | env->ThrowUVException(UV_ENOENT, "Failed to load '%s'.", path.c_str()); |
496 | 0 | break; |
497 | 0 | } |
498 | 0 | default: |
499 | 0 | UNREACHABLE(); |
500 | 0 | } |
501 | 0 | } |
502 | | |
503 | | namespace process { |
504 | | |
505 | | BindingData::BindingData(Realm* realm, |
506 | | v8::Local<v8::Object> object, |
507 | | InternalFieldInfo* info) |
508 | 134k | : SnapshotableObject(realm, object, type_int), |
509 | 134k | hrtime_buffer_(realm->isolate(), |
510 | 134k | kHrTimeBufferLength, |
511 | 134k | MAYBE_FIELD_PTR(info, hrtime_buffer)) { |
512 | 134k | Isolate* isolate = realm->isolate(); |
513 | 134k | Local<Context> context = realm->context(); |
514 | | |
515 | 134k | if (info == nullptr) { |
516 | 134k | object |
517 | 134k | ->Set(context, |
518 | 134k | FIXED_ONE_BYTE_STRING(isolate, "hrtimeBuffer"), |
519 | 134k | hrtime_buffer_.GetJSArray()) |
520 | 134k | .ToChecked(); |
521 | 134k | } else { |
522 | 0 | hrtime_buffer_.Deserialize(realm->context()); |
523 | 0 | } |
524 | | |
525 | | // The hrtime buffer is referenced from the binding data js object. |
526 | | // Make the native handle weak to avoid keeping the realm alive. |
527 | 134k | hrtime_buffer_.MakeWeak(); |
528 | 134k | } |
529 | | |
530 | | v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber)); |
531 | | v8::CFunction BindingData::fast_bigint_(v8::CFunction::Make(FastBigInt)); |
532 | | |
533 | 134k | void BindingData::AddMethods(Isolate* isolate, Local<ObjectTemplate> target) { |
534 | 134k | SetFastMethodNoSideEffect( |
535 | 134k | isolate, target, "hrtime", SlowNumber, &fast_number_); |
536 | 134k | SetFastMethodNoSideEffect( |
537 | 134k | isolate, target, "hrtimeBigInt", SlowBigInt, &fast_bigint_); |
538 | 134k | } |
539 | | |
540 | | void BindingData::RegisterExternalReferences( |
541 | 0 | ExternalReferenceRegistry* registry) { |
542 | 0 | registry->Register(SlowNumber); |
543 | 0 | registry->Register(SlowBigInt); |
544 | 0 | registry->Register(FastNumber); |
545 | 0 | registry->Register(FastBigInt); |
546 | 0 | registry->Register(fast_number_.GetTypeInfo()); |
547 | 0 | registry->Register(fast_bigint_.GetTypeInfo()); |
548 | 0 | } |
549 | | |
550 | 0 | BindingData* BindingData::FromV8Value(Local<Value> value) { |
551 | 0 | Local<Object> v8_object = value.As<Object>(); |
552 | 0 | return static_cast<BindingData*>( |
553 | 0 | v8_object->GetAlignedPointerFromInternalField(BaseObject::kSlot)); |
554 | 0 | } |
555 | | |
556 | 0 | void BindingData::MemoryInfo(MemoryTracker* tracker) const { |
557 | 0 | tracker->TrackField("hrtime_buffer", hrtime_buffer_); |
558 | 0 | } |
559 | | |
560 | | // This is the legacy version of hrtime before BigInt was introduced in |
561 | | // JavaScript. |
562 | | // The value returned by uv_hrtime() is a 64-bit int representing nanoseconds, |
563 | | // so this function instead fills in an Uint32Array with 3 entries, |
564 | | // to avoid any integer overflow possibility. |
565 | | // The first two entries contain the second part of the value |
566 | | // broken into the upper/lower 32 bits to be converted back in JS, |
567 | | // because there is no Uint64Array in JS. |
568 | | // The third entry contains the remaining nanosecond part of the value. |
569 | 0 | void BindingData::NumberImpl(BindingData* receiver) { |
570 | 0 | uint64_t t = uv_hrtime(); |
571 | 0 | receiver->hrtime_buffer_[0] = (t / NANOS_PER_SEC) >> 32; |
572 | 0 | receiver->hrtime_buffer_[1] = (t / NANOS_PER_SEC) & 0xffffffff; |
573 | 0 | receiver->hrtime_buffer_[2] = t % NANOS_PER_SEC; |
574 | 0 | } |
575 | | |
576 | 0 | void BindingData::BigIntImpl(BindingData* receiver) { |
577 | 0 | uint64_t t = uv_hrtime(); |
578 | | // The buffer is a Uint32Array, so we need to reinterpret it as a |
579 | | // Uint64Array to write the value. The buffer is valid at this scope so we |
580 | | // can safely cast away the constness. |
581 | 0 | uint64_t* fields = reinterpret_cast<uint64_t*>( |
582 | 0 | const_cast<uint32_t*>(receiver->hrtime_buffer_.GetNativeBuffer())); |
583 | 0 | fields[0] = t; |
584 | 0 | } |
585 | | |
586 | 0 | void BindingData::SlowBigInt(const FunctionCallbackInfo<Value>& args) { |
587 | 0 | BigIntImpl(FromJSObject<BindingData>(args.Holder())); |
588 | 0 | } |
589 | | |
590 | 0 | void BindingData::SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args) { |
591 | 0 | NumberImpl(FromJSObject<BindingData>(args.Holder())); |
592 | 0 | } |
593 | | |
594 | | bool BindingData::PrepareForSerialization(Local<Context> context, |
595 | 0 | v8::SnapshotCreator* creator) { |
596 | 0 | DCHECK_NULL(internal_field_info_); |
597 | 0 | internal_field_info_ = InternalFieldInfoBase::New<InternalFieldInfo>(type()); |
598 | 0 | internal_field_info_->hrtime_buffer = |
599 | 0 | hrtime_buffer_.Serialize(context, creator); |
600 | | // Return true because we need to maintain the reference to the binding from |
601 | | // JS land. |
602 | 0 | return true; |
603 | 0 | } |
604 | | |
605 | 0 | InternalFieldInfoBase* BindingData::Serialize(int index) { |
606 | 0 | DCHECK_IS_SNAPSHOT_SLOT(index); |
607 | 0 | InternalFieldInfo* info = internal_field_info_; |
608 | 0 | internal_field_info_ = nullptr; |
609 | 0 | return info; |
610 | 0 | } |
611 | | |
612 | | void BindingData::Deserialize(Local<Context> context, |
613 | | Local<Object> holder, |
614 | | int index, |
615 | 0 | InternalFieldInfoBase* info) { |
616 | 0 | DCHECK_IS_SNAPSHOT_SLOT(index); |
617 | 0 | v8::HandleScope scope(context->GetIsolate()); |
618 | 0 | Realm* realm = Realm::GetCurrent(context); |
619 | | // Recreate the buffer in the constructor. |
620 | 0 | InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info); |
621 | 0 | BindingData* binding = |
622 | 0 | realm->AddBindingData<BindingData>(holder, casted_info); |
623 | 0 | CHECK_NOT_NULL(binding); |
624 | 0 | } |
625 | | |
626 | 134k | static void SetEmitWarningSync(const FunctionCallbackInfo<Value>& args) { |
627 | 134k | CHECK(args[0]->IsFunction()); |
628 | 134k | Environment* env = Environment::GetCurrent(args); |
629 | 134k | env->set_process_emit_warning_sync(args[0].As<Function>()); |
630 | 134k | } |
631 | | |
632 | | static void CreatePerIsolateProperties(IsolateData* isolate_data, |
633 | 134k | Local<ObjectTemplate> target) { |
634 | 134k | Isolate* isolate = isolate_data->isolate(); |
635 | | |
636 | 134k | BindingData::AddMethods(isolate, target); |
637 | | // define various internal methods |
638 | 134k | SetMethod(isolate, target, "_debugProcess", DebugProcess); |
639 | 134k | SetMethod(isolate, target, "abort", Abort); |
640 | 134k | SetMethod(isolate, target, "causeSegfault", CauseSegfault); |
641 | 134k | SetMethod(isolate, target, "chdir", Chdir); |
642 | | |
643 | 134k | SetMethod(isolate, target, "umask", Umask); |
644 | 134k | SetMethod(isolate, target, "memoryUsage", MemoryUsage); |
645 | 134k | SetMethod(isolate, target, "constrainedMemory", GetConstrainedMemory); |
646 | 134k | SetMethod(isolate, target, "availableMemory", GetAvailableMemory); |
647 | 134k | SetMethod(isolate, target, "rss", Rss); |
648 | 134k | SetMethod(isolate, target, "cpuUsage", CPUUsage); |
649 | 134k | SetMethod(isolate, target, "resourceUsage", ResourceUsage); |
650 | | |
651 | 134k | SetMethod(isolate, target, "_debugEnd", DebugEnd); |
652 | 134k | SetMethod(isolate, target, "_getActiveRequests", GetActiveRequests); |
653 | 134k | SetMethod(isolate, target, "_getActiveHandles", GetActiveHandles); |
654 | 134k | SetMethod(isolate, target, "getActiveResourcesInfo", GetActiveResourcesInfo); |
655 | 134k | SetMethod(isolate, target, "_kill", Kill); |
656 | 134k | SetMethod(isolate, target, "_rawDebug", RawDebug); |
657 | | |
658 | 134k | SetMethodNoSideEffect(isolate, target, "cwd", Cwd); |
659 | 134k | SetMethod(isolate, target, "dlopen", binding::DLOpen); |
660 | 134k | SetMethod(isolate, target, "reallyExit", ReallyExit); |
661 | 134k | SetMethodNoSideEffect(isolate, target, "uptime", Uptime); |
662 | 134k | SetMethod(isolate, target, "patchProcessObject", PatchProcessObject); |
663 | | |
664 | 134k | SetMethod(isolate, target, "loadEnvFile", LoadEnvFile); |
665 | | |
666 | 134k | SetMethod(isolate, target, "setEmitWarningSync", SetEmitWarningSync); |
667 | 134k | } |
668 | | |
669 | | static void CreatePerContextProperties(Local<Object> target, |
670 | | Local<Value> unused, |
671 | | Local<Context> context, |
672 | 134k | void* priv) { |
673 | 134k | Realm* realm = Realm::GetCurrent(context); |
674 | 134k | realm->AddBindingData<BindingData>(target); |
675 | 134k | } |
676 | | |
677 | 0 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
678 | 0 | BindingData::RegisterExternalReferences(registry); |
679 | |
|
680 | 0 | registry->Register(DebugProcess); |
681 | 0 | registry->Register(DebugEnd); |
682 | 0 | registry->Register(Abort); |
683 | 0 | registry->Register(CauseSegfault); |
684 | 0 | registry->Register(Chdir); |
685 | |
|
686 | 0 | registry->Register(Umask); |
687 | 0 | registry->Register(RawDebug); |
688 | 0 | registry->Register(MemoryUsage); |
689 | 0 | registry->Register(GetConstrainedMemory); |
690 | 0 | registry->Register(GetAvailableMemory); |
691 | 0 | registry->Register(Rss); |
692 | 0 | registry->Register(CPUUsage); |
693 | 0 | registry->Register(ResourceUsage); |
694 | |
|
695 | 0 | registry->Register(GetActiveRequests); |
696 | 0 | registry->Register(GetActiveHandles); |
697 | 0 | registry->Register(GetActiveResourcesInfo); |
698 | 0 | registry->Register(Kill); |
699 | |
|
700 | 0 | registry->Register(Cwd); |
701 | 0 | registry->Register(binding::DLOpen); |
702 | 0 | registry->Register(ReallyExit); |
703 | 0 | registry->Register(Uptime); |
704 | 0 | registry->Register(PatchProcessObject); |
705 | |
|
706 | 0 | registry->Register(LoadEnvFile); |
707 | |
|
708 | 0 | registry->Register(SetEmitWarningSync); |
709 | 0 | } |
710 | | |
711 | | } // namespace process |
712 | | } // namespace node |
713 | | |
714 | | NODE_BINDING_CONTEXT_AWARE_INTERNAL(process_methods, |
715 | | node::process::CreatePerContextProperties) |
716 | | NODE_BINDING_PER_ISOLATE_INIT(process_methods, |
717 | | node::process::CreatePerIsolateProperties) |
718 | | NODE_BINDING_EXTERNAL_REFERENCE(process_methods, |
719 | | node::process::RegisterExternalReferences) |