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