GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#include "node.h" |
||
2 |
#include "node_buffer.h" |
||
3 |
#include "node_constants.h" |
||
4 |
#include "node_file.h" |
||
5 |
#include "node_http_parser.h" |
||
6 |
#include "node_javascript.h" |
||
7 |
#include "node_version.h" |
||
8 |
#include "node_internals.h" |
||
9 |
#include "node_revert.h" |
||
10 |
#include "node_debug_options.h" |
||
11 |
|||
12 |
#if defined HAVE_PERFCTR |
||
13 |
#include "node_counters.h" |
||
14 |
#endif |
||
15 |
|||
16 |
#if HAVE_OPENSSL |
||
17 |
#include "node_crypto.h" |
||
18 |
#endif |
||
19 |
|||
20 |
#if defined(NODE_HAVE_I18N_SUPPORT) |
||
21 |
#include "node_i18n.h" |
||
22 |
#endif |
||
23 |
|||
24 |
#if defined HAVE_DTRACE || defined HAVE_ETW |
||
25 |
#include "node_dtrace.h" |
||
26 |
#endif |
||
27 |
|||
28 |
#if defined HAVE_LTTNG |
||
29 |
#include "node_lttng.h" |
||
30 |
#endif |
||
31 |
|||
32 |
#include "ares.h" |
||
33 |
#include "async-wrap.h" |
||
34 |
#include "async-wrap-inl.h" |
||
35 |
#include "env.h" |
||
36 |
#include "env-inl.h" |
||
37 |
#include "handle_wrap.h" |
||
38 |
#include "req-wrap.h" |
||
39 |
#include "req-wrap-inl.h" |
||
40 |
#include "string_bytes.h" |
||
41 |
#include "tracing/agent.h" |
||
42 |
#include "util.h" |
||
43 |
#include "uv.h" |
||
44 |
#if NODE_USE_V8_PLATFORM |
||
45 |
#include "libplatform/libplatform.h" |
||
46 |
#endif // NODE_USE_V8_PLATFORM |
||
47 |
#include "v8-debug.h" |
||
48 |
#include "v8-profiler.h" |
||
49 |
#include "zlib.h" |
||
50 |
|||
51 |
#ifdef NODE_ENABLE_VTUNE_PROFILING |
||
52 |
#include "../deps/v8/src/third_party/vtune/v8-vtune.h" |
||
53 |
#endif |
||
54 |
|||
55 |
#include <errno.h> |
||
56 |
#include <limits.h> // PATH_MAX |
||
57 |
#include <locale.h> |
||
58 |
#include <signal.h> |
||
59 |
#include <stdio.h> |
||
60 |
#include <stdlib.h> |
||
61 |
#include <string.h> |
||
62 |
#include <sys/types.h> |
||
63 |
|||
64 |
#include <string> |
||
65 |
#include <vector> |
||
66 |
|||
67 |
#if defined(NODE_HAVE_I18N_SUPPORT) |
||
68 |
#include <unicode/uvernum.h> |
||
69 |
#endif |
||
70 |
|||
71 |
#if defined(LEAK_SANITIZER) |
||
72 |
#include <sanitizer/lsan_interface.h> |
||
73 |
#endif |
||
74 |
|||
75 |
#if defined(_MSC_VER) |
||
76 |
#include <direct.h> |
||
77 |
#include <io.h> |
||
78 |
#define getpid GetCurrentProcessId |
||
79 |
#define umask _umask |
||
80 |
typedef int mode_t; |
||
81 |
#else |
||
82 |
#include <pthread.h> |
||
83 |
#include <sys/resource.h> // getrlimit, setrlimit |
||
84 |
#include <unistd.h> // setuid, getuid |
||
85 |
#endif |
||
86 |
|||
87 |
#if defined(__POSIX__) && !defined(__ANDROID__) |
||
88 |
#include <pwd.h> // getpwnam() |
||
89 |
#include <grp.h> // getgrnam() |
||
90 |
#endif |
||
91 |
|||
92 |
#ifdef __APPLE__ |
||
93 |
#include <crt_externs.h> |
||
94 |
#define environ (*_NSGetEnviron()) |
||
95 |
#elif !defined(_MSC_VER) |
||
96 |
extern char **environ; |
||
97 |
#endif |
||
98 |
|||
99 |
namespace node { |
||
100 |
|||
101 |
using v8::Array; |
||
102 |
using v8::ArrayBuffer; |
||
103 |
using v8::Boolean; |
||
104 |
using v8::Context; |
||
105 |
using v8::EscapableHandleScope; |
||
106 |
using v8::Exception; |
||
107 |
using v8::Float64Array; |
||
108 |
using v8::Function; |
||
109 |
using v8::FunctionCallbackInfo; |
||
110 |
using v8::HandleScope; |
||
111 |
using v8::HeapStatistics; |
||
112 |
using v8::Integer; |
||
113 |
using v8::Isolate; |
||
114 |
using v8::Local; |
||
115 |
using v8::Locker; |
||
116 |
using v8::MaybeLocal; |
||
117 |
using v8::Message; |
||
118 |
using v8::Name; |
||
119 |
using v8::NamedPropertyHandlerConfiguration; |
||
120 |
using v8::Null; |
||
121 |
using v8::Number; |
||
122 |
using v8::Object; |
||
123 |
using v8::ObjectTemplate; |
||
124 |
using v8::Promise; |
||
125 |
using v8::PromiseRejectMessage; |
||
126 |
using v8::PropertyCallbackInfo; |
||
127 |
using v8::ScriptOrigin; |
||
128 |
using v8::SealHandleScope; |
||
129 |
using v8::String; |
||
130 |
using v8::TryCatch; |
||
131 |
using v8::Uint32Array; |
||
132 |
using v8::V8; |
||
133 |
using v8::Value; |
||
134 |
|||
135 |
static bool print_eval = false; |
||
136 |
static bool force_repl = false; |
||
137 |
static bool syntax_check_only = false; |
||
138 |
static bool trace_deprecation = false; |
||
139 |
static bool throw_deprecation = false; |
||
140 |
static bool trace_sync_io = false; |
||
141 |
static bool track_heap_objects = false; |
||
142 |
static const char* eval_string = nullptr; |
||
143 |
static unsigned int preload_module_count = 0; |
||
144 |
static const char** preload_modules = nullptr; |
||
145 |
static const int v8_default_thread_pool_size = 4; |
||
146 |
static int v8_thread_pool_size = v8_default_thread_pool_size; |
||
147 |
static bool prof_process = false; |
||
148 |
static bool v8_is_profiling = false; |
||
149 |
static bool node_is_initialized = false; |
||
150 |
static node_module* modpending; |
||
151 |
static node_module* modlist_builtin; |
||
152 |
static node_module* modlist_linked; |
||
153 |
static node_module* modlist_addon; |
||
154 |
static bool trace_enabled = false; |
||
155 |
static const char* trace_enabled_categories = nullptr; |
||
156 |
|||
157 |
#if defined(NODE_HAVE_I18N_SUPPORT) |
||
158 |
// Path to ICU data (for i18n / Intl) |
||
159 |
static const char* icu_data_dir = nullptr; |
||
160 |
#endif |
||
161 |
|||
162 |
// used by C++ modules as well |
||
163 |
bool no_deprecation = false; |
||
164 |
|||
165 |
#if HAVE_OPENSSL |
||
166 |
# if NODE_FIPS_MODE |
||
167 |
// used by crypto module |
||
168 |
bool enable_fips_crypto = false; |
||
169 |
bool force_fips_crypto = false; |
||
170 |
# endif // NODE_FIPS_MODE |
||
171 |
const char* openssl_config = nullptr; |
||
172 |
#endif // HAVE_OPENSSL |
||
173 |
|||
174 |
// true if process warnings should be suppressed |
||
175 |
bool no_process_warnings = false; |
||
176 |
bool trace_warnings = false; |
||
177 |
|||
178 |
// Set in node.cc by ParseArgs when --preserve-symlinks is used. |
||
179 |
// Used in node_config.cc to set a constant on process.binding('config') |
||
180 |
// that is used by lib/module.js |
||
181 |
bool config_preserve_symlinks = false; |
||
182 |
|||
183 |
bool v8_initialized = false; |
||
184 |
|||
185 |
// process-relative uptime base, initialized at start-up |
||
186 |
static double prog_start_time; |
||
187 |
static bool debugger_running; |
||
188 |
static uv_async_t dispatch_debug_messages_async; |
||
189 |
|||
190 |
1757 |
static Mutex node_isolate_mutex; |
|
191 |
static v8::Isolate* node_isolate; |
||
192 |
static tracing::Agent* tracing_agent; |
||
193 |
|||
194 |
1757 |
static node::DebugOptions debug_options; |
|
195 |
|||
196 |
static struct { |
||
197 |
#if NODE_USE_V8_PLATFORM |
||
198 |
1744 |
void Initialize(int thread_pool_size) { |
|
199 |
1744 |
platform_ = v8::platform::CreateDefaultPlatform(thread_pool_size); |
|
200 |
1744 |
V8::InitializePlatform(platform_); |
|
201 |
1744 |
tracing::TraceEventHelper::SetCurrentPlatform(platform_); |
|
202 |
1744 |
} |
|
203 |
|||
204 |
void PumpMessageLoop(Isolate* isolate) { |
||
205 |
24578 |
v8::platform::PumpMessageLoop(platform_, isolate); |
|
206 |
} |
||
207 |
|||
208 |
void Dispose() { |
||
209 |
✓✗ | 1544 |
delete platform_; |
210 |
1544 |
platform_ = nullptr; |
|
211 |
} |
||
212 |
|||
213 |
#if HAVE_INSPECTOR |
||
214 |
bool StartInspector(Environment *env, const char* script_path, |
||
215 |
const node::DebugOptions& options) { |
||
216 |
14 |
return env->inspector_agent()->Start(platform_, script_path, options); |
|
217 |
} |
||
218 |
#endif // HAVE_INSPECTOR |
||
219 |
|||
220 |
v8::Platform* platform_; |
||
221 |
#else // !NODE_USE_V8_PLATFORM |
||
222 |
void Initialize(int thread_pool_size) {} |
||
223 |
void PumpMessageLoop(Isolate* isolate) {} |
||
224 |
void Dispose() {} |
||
225 |
bool StartInspector(Environment *env, const char* script_path, |
||
226 |
int port, bool wait) { |
||
227 |
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0"); |
||
228 |
return false; // make compiler happy |
||
229 |
} |
||
230 |
#endif // !NODE_USE_V8_PLATFORM |
||
231 |
} v8_platform; |
||
232 |
|||
233 |
#ifdef __POSIX__ |
||
234 |
static uv_sem_t debug_semaphore; |
||
235 |
static const unsigned kMaxSignal = 32; |
||
236 |
#endif |
||
237 |
|||
238 |
78 |
static void PrintErrorString(const char* format, ...) { |
|
239 |
va_list ap; |
||
240 |
78 |
va_start(ap, format); |
|
241 |
#ifdef _WIN32 |
||
242 |
HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); |
||
243 |
|||
244 |
// Check if stderr is something other than a tty/console |
||
245 |
if (stderr_handle == INVALID_HANDLE_VALUE || |
||
246 |
stderr_handle == nullptr || |
||
247 |
uv_guess_handle(_fileno(stderr)) != UV_TTY) { |
||
248 |
vfprintf(stderr, format, ap); |
||
249 |
va_end(ap); |
||
250 |
return; |
||
251 |
} |
||
252 |
|||
253 |
// Fill in any placeholders |
||
254 |
int n = _vscprintf(format, ap); |
||
255 |
std::vector<char> out(n + 1); |
||
256 |
vsprintf(out.data(), format, ap); |
||
257 |
|||
258 |
// Get required wide buffer size |
||
259 |
n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0); |
||
260 |
|||
261 |
std::vector<wchar_t> wbuf(n); |
||
262 |
MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n); |
||
263 |
|||
264 |
// Don't include the null character in the output |
||
265 |
CHECK_GT(n, 0); |
||
266 |
WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr); |
||
267 |
#else |
||
268 |
156 |
vfprintf(stderr, format, ap); |
|
269 |
#endif |
||
270 |
78 |
va_end(ap); |
|
271 |
78 |
} |
|
272 |
|||
273 |
|||
274 |
3126 |
static void CheckImmediate(uv_check_t* handle) { |
|
275 |
3126 |
Environment* env = Environment::from_immediate_check_handle(handle); |
|
276 |
6236 |
HandleScope scope(env->isolate()); |
|
277 |
9362 |
Context::Scope context_scope(env->context()); |
|
278 |
6252 |
MakeCallback(env, env->process_object(), env->immediate_callback_string()); |
|
279 |
3110 |
} |
|
280 |
|||
281 |
|||
282 |
2062 |
static void IdleImmediateDummy(uv_idle_t* handle) { |
|
283 |
// Do nothing. Only for maintaining event loop. |
||
284 |
// TODO(bnoordhuis) Maybe make libuv accept nullptr idle callbacks. |
||
285 |
2062 |
} |
|
286 |
|||
287 |
|||
288 |
static inline const char *errno_string(int errorno) { |
||
289 |
#define ERRNO_CASE(e) case e: return #e; |
||
290 |
✓✗ | 1 |
switch (errorno) { |
291 |
#ifdef EACCES |
||
292 |
ERRNO_CASE(EACCES); |
||
293 |
#endif |
||
294 |
|||
295 |
#ifdef EADDRINUSE |
||
296 |
ERRNO_CASE(EADDRINUSE); |
||
297 |
#endif |
||
298 |
|||
299 |
#ifdef EADDRNOTAVAIL |
||
300 |
ERRNO_CASE(EADDRNOTAVAIL); |
||
301 |
#endif |
||
302 |
|||
303 |
#ifdef EAFNOSUPPORT |
||
304 |
ERRNO_CASE(EAFNOSUPPORT); |
||
305 |
#endif |
||
306 |
|||
307 |
#ifdef EAGAIN |
||
308 |
ERRNO_CASE(EAGAIN); |
||
309 |
#endif |
||
310 |
|||
311 |
#ifdef EWOULDBLOCK |
||
312 |
# if EAGAIN != EWOULDBLOCK |
||
313 |
ERRNO_CASE(EWOULDBLOCK); |
||
314 |
# endif |
||
315 |
#endif |
||
316 |
|||
317 |
#ifdef EALREADY |
||
318 |
ERRNO_CASE(EALREADY); |
||
319 |
#endif |
||
320 |
|||
321 |
#ifdef EBADF |
||
322 |
ERRNO_CASE(EBADF); |
||
323 |
#endif |
||
324 |
|||
325 |
#ifdef EBADMSG |
||
326 |
ERRNO_CASE(EBADMSG); |
||
327 |
#endif |
||
328 |
|||
329 |
#ifdef EBUSY |
||
330 |
ERRNO_CASE(EBUSY); |
||
331 |
#endif |
||
332 |
|||
333 |
#ifdef ECANCELED |
||
334 |
ERRNO_CASE(ECANCELED); |
||
335 |
#endif |
||
336 |
|||
337 |
#ifdef ECHILD |
||
338 |
ERRNO_CASE(ECHILD); |
||
339 |
#endif |
||
340 |
|||
341 |
#ifdef ECONNABORTED |
||
342 |
ERRNO_CASE(ECONNABORTED); |
||
343 |
#endif |
||
344 |
|||
345 |
#ifdef ECONNREFUSED |
||
346 |
ERRNO_CASE(ECONNREFUSED); |
||
347 |
#endif |
||
348 |
|||
349 |
#ifdef ECONNRESET |
||
350 |
ERRNO_CASE(ECONNRESET); |
||
351 |
#endif |
||
352 |
|||
353 |
#ifdef EDEADLK |
||
354 |
ERRNO_CASE(EDEADLK); |
||
355 |
#endif |
||
356 |
|||
357 |
#ifdef EDESTADDRREQ |
||
358 |
ERRNO_CASE(EDESTADDRREQ); |
||
359 |
#endif |
||
360 |
|||
361 |
#ifdef EDOM |
||
362 |
ERRNO_CASE(EDOM); |
||
363 |
#endif |
||
364 |
|||
365 |
#ifdef EDQUOT |
||
366 |
ERRNO_CASE(EDQUOT); |
||
367 |
#endif |
||
368 |
|||
369 |
#ifdef EEXIST |
||
370 |
ERRNO_CASE(EEXIST); |
||
371 |
#endif |
||
372 |
|||
373 |
#ifdef EFAULT |
||
374 |
ERRNO_CASE(EFAULT); |
||
375 |
#endif |
||
376 |
|||
377 |
#ifdef EFBIG |
||
378 |
ERRNO_CASE(EFBIG); |
||
379 |
#endif |
||
380 |
|||
381 |
#ifdef EHOSTUNREACH |
||
382 |
ERRNO_CASE(EHOSTUNREACH); |
||
383 |
#endif |
||
384 |
|||
385 |
#ifdef EIDRM |
||
386 |
ERRNO_CASE(EIDRM); |
||
387 |
#endif |
||
388 |
|||
389 |
#ifdef EILSEQ |
||
390 |
ERRNO_CASE(EILSEQ); |
||
391 |
#endif |
||
392 |
|||
393 |
#ifdef EINPROGRESS |
||
394 |
ERRNO_CASE(EINPROGRESS); |
||
395 |
#endif |
||
396 |
|||
397 |
#ifdef EINTR |
||
398 |
ERRNO_CASE(EINTR); |
||
399 |
#endif |
||
400 |
|||
401 |
#ifdef EINVAL |
||
402 |
ERRNO_CASE(EINVAL); |
||
403 |
#endif |
||
404 |
|||
405 |
#ifdef EIO |
||
406 |
ERRNO_CASE(EIO); |
||
407 |
#endif |
||
408 |
|||
409 |
#ifdef EISCONN |
||
410 |
ERRNO_CASE(EISCONN); |
||
411 |
#endif |
||
412 |
|||
413 |
#ifdef EISDIR |
||
414 |
ERRNO_CASE(EISDIR); |
||
415 |
#endif |
||
416 |
|||
417 |
#ifdef ELOOP |
||
418 |
ERRNO_CASE(ELOOP); |
||
419 |
#endif |
||
420 |
|||
421 |
#ifdef EMFILE |
||
422 |
ERRNO_CASE(EMFILE); |
||
423 |
#endif |
||
424 |
|||
425 |
#ifdef EMLINK |
||
426 |
ERRNO_CASE(EMLINK); |
||
427 |
#endif |
||
428 |
|||
429 |
#ifdef EMSGSIZE |
||
430 |
ERRNO_CASE(EMSGSIZE); |
||
431 |
#endif |
||
432 |
|||
433 |
#ifdef EMULTIHOP |
||
434 |
ERRNO_CASE(EMULTIHOP); |
||
435 |
#endif |
||
436 |
|||
437 |
#ifdef ENAMETOOLONG |
||
438 |
ERRNO_CASE(ENAMETOOLONG); |
||
439 |
#endif |
||
440 |
|||
441 |
#ifdef ENETDOWN |
||
442 |
ERRNO_CASE(ENETDOWN); |
||
443 |
#endif |
||
444 |
|||
445 |
#ifdef ENETRESET |
||
446 |
ERRNO_CASE(ENETRESET); |
||
447 |
#endif |
||
448 |
|||
449 |
#ifdef ENETUNREACH |
||
450 |
ERRNO_CASE(ENETUNREACH); |
||
451 |
#endif |
||
452 |
|||
453 |
#ifdef ENFILE |
||
454 |
ERRNO_CASE(ENFILE); |
||
455 |
#endif |
||
456 |
|||
457 |
#ifdef ENOBUFS |
||
458 |
ERRNO_CASE(ENOBUFS); |
||
459 |
#endif |
||
460 |
|||
461 |
#ifdef ENODATA |
||
462 |
ERRNO_CASE(ENODATA); |
||
463 |
#endif |
||
464 |
|||
465 |
#ifdef ENODEV |
||
466 |
ERRNO_CASE(ENODEV); |
||
467 |
#endif |
||
468 |
|||
469 |
#ifdef ENOENT |
||
470 |
ERRNO_CASE(ENOENT); |
||
471 |
#endif |
||
472 |
|||
473 |
#ifdef ENOEXEC |
||
474 |
ERRNO_CASE(ENOEXEC); |
||
475 |
#endif |
||
476 |
|||
477 |
#ifdef ENOLINK |
||
478 |
ERRNO_CASE(ENOLINK); |
||
479 |
#endif |
||
480 |
|||
481 |
#ifdef ENOLCK |
||
482 |
# if ENOLINK != ENOLCK |
||
483 |
ERRNO_CASE(ENOLCK); |
||
484 |
# endif |
||
485 |
#endif |
||
486 |
|||
487 |
#ifdef ENOMEM |
||
488 |
ERRNO_CASE(ENOMEM); |
||
489 |
#endif |
||
490 |
|||
491 |
#ifdef ENOMSG |
||
492 |
ERRNO_CASE(ENOMSG); |
||
493 |
#endif |
||
494 |
|||
495 |
#ifdef ENOPROTOOPT |
||
496 |
ERRNO_CASE(ENOPROTOOPT); |
||
497 |
#endif |
||
498 |
|||
499 |
#ifdef ENOSPC |
||
500 |
ERRNO_CASE(ENOSPC); |
||
501 |
#endif |
||
502 |
|||
503 |
#ifdef ENOSR |
||
504 |
ERRNO_CASE(ENOSR); |
||
505 |
#endif |
||
506 |
|||
507 |
#ifdef ENOSTR |
||
508 |
ERRNO_CASE(ENOSTR); |
||
509 |
#endif |
||
510 |
|||
511 |
#ifdef ENOSYS |
||
512 |
ERRNO_CASE(ENOSYS); |
||
513 |
#endif |
||
514 |
|||
515 |
#ifdef ENOTCONN |
||
516 |
ERRNO_CASE(ENOTCONN); |
||
517 |
#endif |
||
518 |
|||
519 |
#ifdef ENOTDIR |
||
520 |
ERRNO_CASE(ENOTDIR); |
||
521 |
#endif |
||
522 |
|||
523 |
#ifdef ENOTEMPTY |
||
524 |
# if ENOTEMPTY != EEXIST |
||
525 |
ERRNO_CASE(ENOTEMPTY); |
||
526 |
# endif |
||
527 |
#endif |
||
528 |
|||
529 |
#ifdef ENOTSOCK |
||
530 |
ERRNO_CASE(ENOTSOCK); |
||
531 |
#endif |
||
532 |
|||
533 |
#ifdef ENOTSUP |
||
534 |
ERRNO_CASE(ENOTSUP); |
||
535 |
#else |
||
536 |
# ifdef EOPNOTSUPP |
||
537 |
ERRNO_CASE(EOPNOTSUPP); |
||
538 |
# endif |
||
539 |
#endif |
||
540 |
|||
541 |
#ifdef ENOTTY |
||
542 |
ERRNO_CASE(ENOTTY); |
||
543 |
#endif |
||
544 |
|||
545 |
#ifdef ENXIO |
||
546 |
ERRNO_CASE(ENXIO); |
||
547 |
#endif |
||
548 |
|||
549 |
|||
550 |
#ifdef EOVERFLOW |
||
551 |
ERRNO_CASE(EOVERFLOW); |
||
552 |
#endif |
||
553 |
|||
554 |
#ifdef EPERM |
||
555 |
ERRNO_CASE(EPERM); |
||
556 |
#endif |
||
557 |
|||
558 |
#ifdef EPIPE |
||
559 |
ERRNO_CASE(EPIPE); |
||
560 |
#endif |
||
561 |
|||
562 |
#ifdef EPROTO |
||
563 |
ERRNO_CASE(EPROTO); |
||
564 |
#endif |
||
565 |
|||
566 |
#ifdef EPROTONOSUPPORT |
||
567 |
ERRNO_CASE(EPROTONOSUPPORT); |
||
568 |
#endif |
||
569 |
|||
570 |
#ifdef EPROTOTYPE |
||
571 |
ERRNO_CASE(EPROTOTYPE); |
||
572 |
#endif |
||
573 |
|||
574 |
#ifdef ERANGE |
||
575 |
ERRNO_CASE(ERANGE); |
||
576 |
#endif |
||
577 |
|||
578 |
#ifdef EROFS |
||
579 |
ERRNO_CASE(EROFS); |
||
580 |
#endif |
||
581 |
|||
582 |
#ifdef ESPIPE |
||
583 |
ERRNO_CASE(ESPIPE); |
||
584 |
#endif |
||
585 |
|||
586 |
#ifdef ESRCH |
||
587 |
ERRNO_CASE(ESRCH); |
||
588 |
#endif |
||
589 |
|||
590 |
#ifdef ESTALE |
||
591 |
ERRNO_CASE(ESTALE); |
||
592 |
#endif |
||
593 |
|||
594 |
#ifdef ETIME |
||
595 |
ERRNO_CASE(ETIME); |
||
596 |
#endif |
||
597 |
|||
598 |
#ifdef ETIMEDOUT |
||
599 |
ERRNO_CASE(ETIMEDOUT); |
||
600 |
#endif |
||
601 |
|||
602 |
#ifdef ETXTBSY |
||
603 |
ERRNO_CASE(ETXTBSY); |
||
604 |
#endif |
||
605 |
|||
606 |
#ifdef EXDEV |
||
607 |
ERRNO_CASE(EXDEV); |
||
608 |
#endif |
||
609 |
|||
610 |
default: return ""; |
||
611 |
} |
||
612 |
} |
||
613 |
|||
614 |
682 |
const char *signo_string(int signo) { |
|
615 |
#define SIGNO_CASE(e) case e: return #e; |
||
616 |
✓✓ | 682 |
switch (signo) { |
617 |
#ifdef SIGHUP |
||
618 |
SIGNO_CASE(SIGHUP); |
||
619 |
#endif |
||
620 |
|||
621 |
#ifdef SIGINT |
||
622 |
SIGNO_CASE(SIGINT); |
||
623 |
#endif |
||
624 |
|||
625 |
#ifdef SIGQUIT |
||
626 |
SIGNO_CASE(SIGQUIT); |
||
627 |
#endif |
||
628 |
|||
629 |
#ifdef SIGILL |
||
630 |
SIGNO_CASE(SIGILL); |
||
631 |
#endif |
||
632 |
|||
633 |
#ifdef SIGTRAP |
||
634 |
SIGNO_CASE(SIGTRAP); |
||
635 |
#endif |
||
636 |
|||
637 |
#ifdef SIGABRT |
||
638 |
SIGNO_CASE(SIGABRT); |
||
639 |
#endif |
||
640 |
|||
641 |
#ifdef SIGIOT |
||
642 |
# if SIGABRT != SIGIOT |
||
643 |
SIGNO_CASE(SIGIOT); |
||
644 |
# endif |
||
645 |
#endif |
||
646 |
|||
647 |
#ifdef SIGBUS |
||
648 |
SIGNO_CASE(SIGBUS); |
||
649 |
#endif |
||
650 |
|||
651 |
#ifdef SIGFPE |
||
652 |
SIGNO_CASE(SIGFPE); |
||
653 |
#endif |
||
654 |
|||
655 |
#ifdef SIGKILL |
||
656 |
SIGNO_CASE(SIGKILL); |
||
657 |
#endif |
||
658 |
|||
659 |
#ifdef SIGUSR1 |
||
660 |
SIGNO_CASE(SIGUSR1); |
||
661 |
#endif |
||
662 |
|||
663 |
#ifdef SIGSEGV |
||
664 |
SIGNO_CASE(SIGSEGV); |
||
665 |
#endif |
||
666 |
|||
667 |
#ifdef SIGUSR2 |
||
668 |
SIGNO_CASE(SIGUSR2); |
||
669 |
#endif |
||
670 |
|||
671 |
#ifdef SIGPIPE |
||
672 |
SIGNO_CASE(SIGPIPE); |
||
673 |
#endif |
||
674 |
|||
675 |
#ifdef SIGALRM |
||
676 |
SIGNO_CASE(SIGALRM); |
||
677 |
#endif |
||
678 |
|||
679 |
SIGNO_CASE(SIGTERM); |
||
680 |
|||
681 |
#ifdef SIGCHLD |
||
682 |
SIGNO_CASE(SIGCHLD); |
||
683 |
#endif |
||
684 |
|||
685 |
#ifdef SIGSTKFLT |
||
686 |
SIGNO_CASE(SIGSTKFLT); |
||
687 |
#endif |
||
688 |
|||
689 |
|||
690 |
#ifdef SIGCONT |
||
691 |
SIGNO_CASE(SIGCONT); |
||
692 |
#endif |
||
693 |
|||
694 |
#ifdef SIGSTOP |
||
695 |
SIGNO_CASE(SIGSTOP); |
||
696 |
#endif |
||
697 |
|||
698 |
#ifdef SIGTSTP |
||
699 |
SIGNO_CASE(SIGTSTP); |
||
700 |
#endif |
||
701 |
|||
702 |
#ifdef SIGBREAK |
||
703 |
SIGNO_CASE(SIGBREAK); |
||
704 |
#endif |
||
705 |
|||
706 |
#ifdef SIGTTIN |
||
707 |
SIGNO_CASE(SIGTTIN); |
||
708 |
#endif |
||
709 |
|||
710 |
#ifdef SIGTTOU |
||
711 |
SIGNO_CASE(SIGTTOU); |
||
712 |
#endif |
||
713 |
|||
714 |
#ifdef SIGURG |
||
715 |
SIGNO_CASE(SIGURG); |
||
716 |
#endif |
||
717 |
|||
718 |
#ifdef SIGXCPU |
||
719 |
SIGNO_CASE(SIGXCPU); |
||
720 |
#endif |
||
721 |
|||
722 |
#ifdef SIGXFSZ |
||
723 |
SIGNO_CASE(SIGXFSZ); |
||
724 |
#endif |
||
725 |
|||
726 |
#ifdef SIGVTALRM |
||
727 |
SIGNO_CASE(SIGVTALRM); |
||
728 |
#endif |
||
729 |
|||
730 |
#ifdef SIGPROF |
||
731 |
SIGNO_CASE(SIGPROF); |
||
732 |
#endif |
||
733 |
|||
734 |
#ifdef SIGWINCH |
||
735 |
SIGNO_CASE(SIGWINCH); |
||
736 |
#endif |
||
737 |
|||
738 |
#ifdef SIGIO |
||
739 |
SIGNO_CASE(SIGIO); |
||
740 |
#endif |
||
741 |
|||
742 |
#ifdef SIGPOLL |
||
743 |
# if SIGPOLL != SIGIO |
||
744 |
SIGNO_CASE(SIGPOLL); |
||
745 |
# endif |
||
746 |
#endif |
||
747 |
|||
748 |
#ifdef SIGLOST |
||
749 |
# if SIGLOST != SIGABRT |
||
750 |
SIGNO_CASE(SIGLOST); |
||
751 |
# endif |
||
752 |
#endif |
||
753 |
|||
754 |
#ifdef SIGPWR |
||
755 |
# if SIGPWR != SIGLOST |
||
756 |
SIGNO_CASE(SIGPWR); |
||
757 |
# endif |
||
758 |
#endif |
||
759 |
|||
760 |
#ifdef SIGINFO |
||
761 |
# if !defined(SIGPWR) || SIGINFO != SIGPWR |
||
762 |
SIGNO_CASE(SIGINFO); |
||
763 |
# endif |
||
764 |
#endif |
||
765 |
|||
766 |
#ifdef SIGSYS |
||
767 |
SIGNO_CASE(SIGSYS); |
||
768 |
#endif |
||
769 |
|||
770 |
default: return ""; |
||
771 |
} |
||
772 |
} |
||
773 |
|||
774 |
|||
775 |
1 |
Local<Value> ErrnoException(Isolate* isolate, |
|
776 |
int errorno, |
||
777 |
const char *syscall, |
||
778 |
const char *msg, |
||
779 |
const char *path) { |
||
780 |
1 |
Environment* env = Environment::GetCurrent(isolate); |
|
781 |
|||
782 |
1 |
Local<Value> e; |
|
783 |
1 |
Local<String> estring = OneByteString(env->isolate(), errno_string(errorno)); |
|
784 |
✗✓✗✗ |
1 |
if (msg == nullptr || msg[0] == '\0') { |
785 |
1 |
msg = strerror(errorno); |
|
786 |
} |
||
787 |
1 |
Local<String> message = OneByteString(env->isolate(), msg); |
|
788 |
|||
789 |
Local<String> cons = |
||
790 |
1 |
String::Concat(estring, FIXED_ONE_BYTE_STRING(env->isolate(), ", ")); |
|
791 |
1 |
cons = String::Concat(cons, message); |
|
792 |
|||
793 |
1 |
Local<String> path_string; |
|
794 |
✗✓ | 1 |
if (path != nullptr) { |
795 |
// FIXME(bnoordhuis) It's questionable to interpret the file path as UTF-8. |
||
796 |
path_string = String::NewFromUtf8(env->isolate(), path); |
||
797 |
} |
||
798 |
|||
799 |
✗✓ | 1 |
if (path_string.IsEmpty() == false) { |
800 |
cons = String::Concat(cons, FIXED_ONE_BYTE_STRING(env->isolate(), " '")); |
||
801 |
cons = String::Concat(cons, path_string); |
||
802 |
cons = String::Concat(cons, FIXED_ONE_BYTE_STRING(env->isolate(), "'")); |
||
803 |
} |
||
804 |
1 |
e = Exception::Error(cons); |
|
805 |
|||
806 |
1 |
Local<Object> obj = e->ToObject(env->isolate()); |
|
807 |
4 |
obj->Set(env->errno_string(), Integer::New(env->isolate(), errorno)); |
|
808 |
3 |
obj->Set(env->code_string(), estring); |
|
809 |
|||
810 |
✗✓ | 1 |
if (path_string.IsEmpty() == false) { |
811 |
obj->Set(env->path_string(), path_string); |
||
812 |
} |
||
813 |
|||
814 |
✓✗ | 1 |
if (syscall != nullptr) { |
815 |
4 |
obj->Set(env->syscall_string(), OneByteString(env->isolate(), syscall)); |
|
816 |
} |
||
817 |
|||
818 |
1 |
return e; |
|
819 |
} |
||
820 |
|||
821 |
|||
822 |
static Local<String> StringFromPath(Isolate* isolate, const char* path) { |
||
823 |
#ifdef _WIN32 |
||
824 |
if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) { |
||
825 |
return String::Concat(FIXED_ONE_BYTE_STRING(isolate, "\\\\"), |
||
826 |
String::NewFromUtf8(isolate, path + 8)); |
||
827 |
} else if (strncmp(path, "\\\\?\\", 4) == 0) { |
||
828 |
return String::NewFromUtf8(isolate, path + 4); |
||
829 |
} |
||
830 |
#endif |
||
831 |
|||
832 |
2508 |
return String::NewFromUtf8(isolate, path); |
|
833 |
} |
||
834 |
|||
835 |
|||
836 |
Local<Value> UVException(Isolate* isolate, |
||
837 |
int errorno, |
||
838 |
const char* syscall, |
||
839 |
const char* msg, |
||
840 |
const char* path) { |
||
841 |
return UVException(isolate, errorno, syscall, msg, path, nullptr); |
||
842 |
} |
||
843 |
|||
844 |
|||
845 |
2518 |
Local<Value> UVException(Isolate* isolate, |
|
846 |
int errorno, |
||
847 |
const char* syscall, |
||
848 |
const char* msg, |
||
849 |
const char* path, |
||
850 |
const char* dest) { |
||
851 |
2518 |
Environment* env = Environment::GetCurrent(isolate); |
|
852 |
|||
853 |
✗✓✗✗ |
2518 |
if (!msg || !msg[0]) |
854 |
2518 |
msg = uv_strerror(errorno); |
|
855 |
|||
856 |
2518 |
Local<String> js_code = OneByteString(isolate, uv_err_name(errorno)); |
|
857 |
2518 |
Local<String> js_syscall = OneByteString(isolate, syscall); |
|
858 |
2518 |
Local<String> js_path; |
|
859 |
2518 |
Local<String> js_dest; |
|
860 |
|||
861 |
2518 |
Local<String> js_msg = js_code; |
|
862 |
2518 |
js_msg = String::Concat(js_msg, FIXED_ONE_BYTE_STRING(isolate, ": ")); |
|
863 |
2518 |
js_msg = String::Concat(js_msg, OneByteString(isolate, msg)); |
|
864 |
2518 |
js_msg = String::Concat(js_msg, FIXED_ONE_BYTE_STRING(isolate, ", ")); |
|
865 |
2518 |
js_msg = String::Concat(js_msg, js_syscall); |
|
866 |
|||
867 |
✓✓ | 2518 |
if (path != nullptr) { |
868 |
2498 |
js_path = StringFromPath(isolate, path); |
|
869 |
|||
870 |
2498 |
js_msg = String::Concat(js_msg, FIXED_ONE_BYTE_STRING(isolate, " '")); |
|
871 |
2498 |
js_msg = String::Concat(js_msg, js_path); |
|
872 |
2498 |
js_msg = String::Concat(js_msg, FIXED_ONE_BYTE_STRING(isolate, "'")); |
|
873 |
} |
||
874 |
|||
875 |
✓✓ | 2518 |
if (dest != nullptr) { |
876 |
10 |
js_dest = StringFromPath(isolate, dest); |
|
877 |
|||
878 |
10 |
js_msg = String::Concat(js_msg, FIXED_ONE_BYTE_STRING(isolate, " -> '")); |
|
879 |
10 |
js_msg = String::Concat(js_msg, js_dest); |
|
880 |
10 |
js_msg = String::Concat(js_msg, FIXED_ONE_BYTE_STRING(isolate, "'")); |
|
881 |
} |
||
882 |
|||
883 |
5036 |
Local<Object> e = Exception::Error(js_msg)->ToObject(isolate); |
|
884 |
|||
885 |
// TODO(piscisaureus) errno should probably go; the user has no way of |
||
886 |
// knowing which uv errno value maps to which error. |
||
887 |
10072 |
e->Set(env->errno_string(), Integer::New(isolate, errorno)); |
|
888 |
7554 |
e->Set(env->code_string(), js_code); |
|
889 |
7554 |
e->Set(env->syscall_string(), js_syscall); |
|
890 |
✓✓ | 2518 |
if (!js_path.IsEmpty()) |
891 |
7494 |
e->Set(env->path_string(), js_path); |
|
892 |
✓✓ | 2518 |
if (!js_dest.IsEmpty()) |
893 |
30 |
e->Set(env->dest_string(), js_dest); |
|
894 |
|||
895 |
2518 |
return e; |
|
896 |
} |
||
897 |
|||
898 |
|||
899 |
// Look up environment variable unless running as setuid root. |
||
900 |
5255 |
inline const char* secure_getenv(const char* key) { |
|
901 |
#ifndef _WIN32 |
||
902 |
✓✗✗✓ ✓✗ |
5255 |
if (getuid() != geteuid() || getgid() != getegid()) |
903 |
return nullptr; |
||
904 |
#endif |
||
905 |
5255 |
return getenv(key); |
|
906 |
} |
||
907 |
|||
908 |
|||
909 |
#ifdef _WIN32 |
||
910 |
// Does about the same as strerror(), |
||
911 |
// but supports all windows error messages |
||
912 |
static const char *winapi_strerror(const int errorno, bool* must_free) { |
||
913 |
char *errmsg = nullptr; |
||
914 |
|||
915 |
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
||
916 |
FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, errorno, |
||
917 |
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errmsg, 0, nullptr); |
||
918 |
|||
919 |
if (errmsg) { |
||
920 |
*must_free = true; |
||
921 |
|||
922 |
// Remove trailing newlines |
||
923 |
for (int i = strlen(errmsg) - 1; |
||
924 |
i >= 0 && (errmsg[i] == '\n' || errmsg[i] == '\r'); i--) { |
||
925 |
errmsg[i] = '\0'; |
||
926 |
} |
||
927 |
|||
928 |
return errmsg; |
||
929 |
} else { |
||
930 |
// FormatMessage failed |
||
931 |
*must_free = false; |
||
932 |
return "Unknown error"; |
||
933 |
} |
||
934 |
} |
||
935 |
|||
936 |
|||
937 |
Local<Value> WinapiErrnoException(Isolate* isolate, |
||
938 |
int errorno, |
||
939 |
const char* syscall, |
||
940 |
const char* msg, |
||
941 |
const char* path) { |
||
942 |
Environment* env = Environment::GetCurrent(isolate); |
||
943 |
Local<Value> e; |
||
944 |
bool must_free = false; |
||
945 |
if (!msg || !msg[0]) { |
||
946 |
msg = winapi_strerror(errorno, &must_free); |
||
947 |
} |
||
948 |
Local<String> message = OneByteString(env->isolate(), msg); |
||
949 |
|||
950 |
if (path) { |
||
951 |
Local<String> cons1 = |
||
952 |
String::Concat(message, FIXED_ONE_BYTE_STRING(isolate, " '")); |
||
953 |
Local<String> cons2 = |
||
954 |
String::Concat(cons1, String::NewFromUtf8(isolate, path)); |
||
955 |
Local<String> cons3 = |
||
956 |
String::Concat(cons2, FIXED_ONE_BYTE_STRING(isolate, "'")); |
||
957 |
e = Exception::Error(cons3); |
||
958 |
} else { |
||
959 |
e = Exception::Error(message); |
||
960 |
} |
||
961 |
|||
962 |
Local<Object> obj = e->ToObject(env->isolate()); |
||
963 |
obj->Set(env->errno_string(), Integer::New(isolate, errorno)); |
||
964 |
|||
965 |
if (path != nullptr) { |
||
966 |
obj->Set(env->path_string(), String::NewFromUtf8(isolate, path)); |
||
967 |
} |
||
968 |
|||
969 |
if (syscall != nullptr) { |
||
970 |
obj->Set(env->syscall_string(), OneByteString(isolate, syscall)); |
||
971 |
} |
||
972 |
|||
973 |
if (must_free) |
||
974 |
LocalFree((HLOCAL)msg); |
||
975 |
|||
976 |
return e; |
||
977 |
} |
||
978 |
#endif |
||
979 |
|||
980 |
|||
981 |
13873 |
void* ArrayBufferAllocator::Allocate(size_t size) { |
|
982 |
✓✓✓✓ |
13873 |
if (zero_fill_field_ || zero_fill_all_buffers) |
983 |
5542 |
return node::UncheckedCalloc(size); |
|
984 |
else |
||
985 |
8331 |
return node::UncheckedMalloc(size); |
|
986 |
} |
||
987 |
|||
988 |
28 |
static bool DomainHasErrorHandler(const Environment* env, |
|
989 |
const Local<Object>& domain) { |
||
990 |
56 |
HandleScope scope(env->isolate()); |
|
991 |
|||
992 |
84 |
Local<Value> domain_event_listeners_v = domain->Get(env->events_string()); |
|
993 |
✓✗ | 28 |
if (!domain_event_listeners_v->IsObject()) |
994 |
return false; |
||
995 |
|||
996 |
Local<Object> domain_event_listeners_o = |
||
997 |
28 |
domain_event_listeners_v.As<Object>(); |
|
998 |
|||
999 |
Local<Value> domain_error_listeners_v = |
||
1000 |
56 |
domain_event_listeners_o->Get(env->error_string()); |
|
1001 |
|||
1002 |
✓✓✗✓ ✓✓ |
57 |
if (domain_error_listeners_v->IsFunction() || |
1003 |
✗✗ | 1 |
(domain_error_listeners_v->IsArray() && |
1004 |
domain_error_listeners_v.As<Array>()->Length() > 0)) |
||
1005 |
return true; |
||
1006 |
|||
1007 |
1 |
return false; |
|
1008 |
} |
||
1009 |
|||
1010 |
27 |
static bool DomainsStackHasErrorHandler(const Environment* env) { |
|
1011 |
54 |
HandleScope scope(env->isolate()); |
|
1012 |
|||
1013 |
✓✗ | 27 |
if (!env->using_domains()) |
1014 |
return false; |
||
1015 |
|||
1016 |
54 |
Local<Array> domains_stack_array = env->domains_stack_array().As<Array>(); |
|
1017 |
✓✗ | 27 |
if (domains_stack_array->Length() == 0) |
1018 |
return false; |
||
1019 |
|||
1020 |
27 |
uint32_t domains_stack_length = domains_stack_array->Length(); |
|
1021 |
✓✗ | 28 |
for (uint32_t i = domains_stack_length; i > 0; --i) { |
1022 |
28 |
Local<Value> domain_v = domains_stack_array->Get(i - 1); |
|
1023 |
✓✗ | 28 |
if (!domain_v->IsObject()) |
1024 |
27 |
return false; |
|
1025 |
|||
1026 |
28 |
Local<Object> domain = domain_v.As<Object>(); |
|
1027 |
✓✓ | 28 |
if (DomainHasErrorHandler(env, domain)) |
1028 |
return true; |
||
1029 |
} |
||
1030 |
|||
1031 |
return false; |
||
1032 |
} |
||
1033 |
|||
1034 |
|||
1035 |
27 |
static bool ShouldAbortOnUncaughtException(Isolate* isolate) { |
|
1036 |
54 |
HandleScope scope(isolate); |
|
1037 |
|||
1038 |
27 |
Environment* env = Environment::GetCurrent(isolate); |
|
1039 |
27 |
Local<Object> process_object = env->process_object(); |
|
1040 |
Local<String> emitting_top_level_domain_error_key = |
||
1041 |
27 |
env->emitting_top_level_domain_error_string(); |
|
1042 |
bool isEmittingTopLevelDomainError = |
||
1043 |
54 |
process_object->Get(emitting_top_level_domain_error_key)->BooleanValue(); |
|
1044 |
|||
1045 |
✓✗✗✓ |
54 |
return isEmittingTopLevelDomainError || !DomainsStackHasErrorHandler(env); |
1046 |
} |
||
1047 |
|||
1048 |
|||
1049 |
139 |
void SetupDomainUse(const FunctionCallbackInfo<Value>& args) { |
|
1050 |
139 |
Environment* env = Environment::GetCurrent(args); |
|
1051 |
|||
1052 |
✓✗ | 139 |
if (env->using_domains()) |
1053 |
return; |
||
1054 |
139 |
env->set_using_domains(true); |
|
1055 |
|||
1056 |
278 |
HandleScope scope(env->isolate()); |
|
1057 |
139 |
Local<Object> process_object = env->process_object(); |
|
1058 |
|||
1059 |
139 |
Local<String> tick_callback_function_key = env->tick_domain_cb_string(); |
|
1060 |
Local<Function> tick_callback_function = |
||
1061 |
278 |
process_object->Get(tick_callback_function_key).As<Function>(); |
|
1062 |
|||
1063 |
✗✓ | 139 |
if (!tick_callback_function->IsFunction()) { |
1064 |
fprintf(stderr, "process._tickDomainCallback assigned to non-function\n"); |
||
1065 |
ABORT(); |
||
1066 |
} |
||
1067 |
|||
1068 |
417 |
process_object->Set(env->tick_callback_string(), tick_callback_function); |
|
1069 |
139 |
env->set_tick_callback_function(tick_callback_function); |
|
1070 |
|||
1071 |
✗✓ | 139 |
CHECK(args[0]->IsArray()); |
1072 |
278 |
env->set_domain_array(args[0].As<Array>()); |
|
1073 |
|||
1074 |
✗✓ | 139 |
CHECK(args[1]->IsArray()); |
1075 |
278 |
env->set_domains_stack_array(args[1].As<Array>()); |
|
1076 |
|||
1077 |
// Do a little housekeeping. |
||
1078 |
417 |
env->process_object()->Delete( |
|
1079 |
env->context(), |
||
1080 |
973 |
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupDomainUse")).FromJust(); |
|
1081 |
|||
1082 |
278 |
uint32_t* const fields = env->domain_flag()->fields(); |
|
1083 |
139 |
uint32_t const fields_count = env->domain_flag()->fields_count(); |
|
1084 |
|||
1085 |
Local<ArrayBuffer> array_buffer = |
||
1086 |
139 |
ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count); |
|
1087 |
|||
1088 |
417 |
args.GetReturnValue().Set(Uint32Array::New(array_buffer, 0, fields_count)); |
|
1089 |
} |
||
1090 |
|||
1091 |
32692 |
void RunMicrotasks(const FunctionCallbackInfo<Value>& args) { |
|
1092 |
32692 |
args.GetIsolate()->RunMicrotasks(); |
|
1093 |
32692 |
} |
|
1094 |
|||
1095 |
|||
1096 |
1750 |
void SetupProcessObject(const FunctionCallbackInfo<Value>& args) { |
|
1097 |
1750 |
Environment* env = Environment::GetCurrent(args); |
|
1098 |
|||
1099 |
✗✓ | 1750 |
CHECK(args[0]->IsFunction()); |
1100 |
|||
1101 |
3500 |
env->set_push_values_to_array_function(args[0].As<Function>()); |
|
1102 |
5250 |
env->process_object()->Delete( |
|
1103 |
env->context(), |
||
1104 |
10500 |
FIXED_ONE_BYTE_STRING(env->isolate(), "_setupProcessObject")).FromJust(); |
|
1105 |
1750 |
} |
|
1106 |
|||
1107 |
|||
1108 |
1750 |
void SetupNextTick(const FunctionCallbackInfo<Value>& args) { |
|
1109 |
1750 |
Environment* env = Environment::GetCurrent(args); |
|
1110 |
|||
1111 |
✗✓ | 1750 |
CHECK(args[0]->IsFunction()); |
1112 |
✗✓ | 1750 |
CHECK(args[1]->IsObject()); |
1113 |
|||
1114 |
3500 |
env->set_tick_callback_function(args[0].As<Function>()); |
|
1115 |
|||
1116 |
3500 |
env->SetMethod(args[1].As<Object>(), "runMicrotasks", RunMicrotasks); |
|
1117 |
|||
1118 |
// Do a little housekeeping. |
||
1119 |
5250 |
env->process_object()->Delete( |
|
1120 |
env->context(), |
||
1121 |
12250 |
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupNextTick")).FromJust(); |
|
1122 |
|||
1123 |
// Values use to cross communicate with processNextTick. |
||
1124 |
3500 |
uint32_t* const fields = env->tick_info()->fields(); |
|
1125 |
1750 |
uint32_t const fields_count = env->tick_info()->fields_count(); |
|
1126 |
|||
1127 |
Local<ArrayBuffer> array_buffer = |
||
1128 |
1750 |
ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count); |
|
1129 |
|||
1130 |
5250 |
args.GetReturnValue().Set(Uint32Array::New(array_buffer, 0, fields_count)); |
|
1131 |
1750 |
} |
|
1132 |
|||
1133 |
64 |
void PromiseRejectCallback(PromiseRejectMessage message) { |
|
1134 |
64 |
Local<Promise> promise = message.GetPromise(); |
|
1135 |
64 |
Isolate* isolate = promise->GetIsolate(); |
|
1136 |
64 |
Local<Value> value = message.GetValue(); |
|
1137 |
64 |
Local<Integer> event = Integer::New(isolate, message.GetEvent()); |
|
1138 |
|||
1139 |
64 |
Environment* env = Environment::GetCurrent(isolate); |
|
1140 |
64 |
Local<Function> callback = env->promise_reject_function(); |
|
1141 |
|||
1142 |
✓✓ | 64 |
if (value.IsEmpty()) |
1143 |
50 |
value = Undefined(isolate); |
|
1144 |
|||
1145 |
192 |
Local<Value> args[] = { event, promise, value }; |
|
1146 |
64 |
Local<Object> process = env->process_object(); |
|
1147 |
|||
1148 |
128 |
callback->Call(process, arraysize(args), args); |
|
1149 |
64 |
} |
|
1150 |
|||
1151 |
1750 |
void SetupPromises(const FunctionCallbackInfo<Value>& args) { |
|
1152 |
1750 |
Environment* env = Environment::GetCurrent(args); |
|
1153 |
1750 |
Isolate* isolate = env->isolate(); |
|
1154 |
|||
1155 |
✗✓ | 1750 |
CHECK(args[0]->IsFunction()); |
1156 |
|||
1157 |
1750 |
isolate->SetPromiseRejectCallback(PromiseRejectCallback); |
|
1158 |
3500 |
env->set_promise_reject_function(args[0].As<Function>()); |
|
1159 |
|||
1160 |
5250 |
env->process_object()->Delete( |
|
1161 |
env->context(), |
||
1162 |
12250 |
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupPromises")).FromJust(); |
|
1163 |
1750 |
} |
|
1164 |
|||
1165 |
|||
1166 |
6276 |
Local<Value> MakeCallback(Environment* env, |
|
1167 |
Local<Value> recv, |
||
1168 |
const Local<Function> callback, |
||
1169 |
int argc, |
||
1170 |
Local<Value> argv[]) { |
||
1171 |
// If you hit this assertion, you forgot to enter the v8::Context first. |
||
1172 |
✗✓ | 18828 |
CHECK_EQ(env->context(), env->isolate()->GetCurrentContext()); |
1173 |
|||
1174 |
6276 |
Local<Function> pre_fn = env->async_hooks_pre_function(); |
|
1175 |
6276 |
Local<Function> post_fn = env->async_hooks_post_function(); |
|
1176 |
12552 |
Local<Object> object, domain; |
|
1177 |
6276 |
bool ran_init_callback = false; |
|
1178 |
6276 |
bool has_domain = false; |
|
1179 |
|||
1180 |
12534 |
Environment::AsyncCallbackScope callback_scope(env); |
|
1181 |
|||
1182 |
// TODO(trevnorris): Adding "_asyncQueue" to the "this" in the init callback |
||
1183 |
// is a horrible way to detect usage. Rethink how detection should happen. |
||
1184 |
✓✗ | 6276 |
if (recv->IsObject()) { |
1185 |
6276 |
object = recv.As<Object>(); |
|
1186 |
12552 |
Local<Value> async_queue_v = object->Get(env->async_queue_string()); |
|
1187 |
✗✓ | 6276 |
if (async_queue_v->IsObject()) |
1188 |
ran_init_callback = true; |
||
1189 |
} |
||
1190 |
|||
1191 |
✓✓ | 6276 |
if (env->using_domains()) { |
1192 |
✗✓ | 1419 |
CHECK(recv->IsObject()); |
1193 |
2838 |
Local<Value> domain_v = object->Get(env->domain_string()); |
|
1194 |
1419 |
has_domain = domain_v->IsObject(); |
|
1195 |
✓✓ | 1419 |
if (has_domain) { |
1196 |
13 |
domain = domain_v.As<Object>(); |
|
1197 |
✗✓ | 39 |
if (domain->Get(env->disposed_string())->IsTrue()) |
1198 |
return Undefined(env->isolate()); |
||
1199 |
} |
||
1200 |
} |
||
1201 |
|||
1202 |
✓✓ | 6276 |
if (has_domain) { |
1203 |
26 |
Local<Value> enter_v = domain->Get(env->enter_string()); |
|
1204 |
✓✗ | 13 |
if (enter_v->IsFunction()) { |
1205 |
✗✓ | 39 |
if (enter_v.As<Function>()->Call(domain, 0, nullptr).IsEmpty()) { |
1206 |
FatalError("node::MakeCallback", |
||
1207 |
"domain enter callback threw, please report this"); |
||
1208 |
} |
||
1209 |
} |
||
1210 |
} |
||
1211 |
|||
1212 |
✗✓✗✗ ✗✓ |
6276 |
if (ran_init_callback && !pre_fn.IsEmpty()) { |
1213 |
TryCatch try_catch(env->isolate()); |
||
1214 |
MaybeLocal<Value> ar = pre_fn->Call(env->context(), object, 0, nullptr); |
||
1215 |
if (ar.IsEmpty()) { |
||
1216 |
ClearFatalExceptionHandlers(env); |
||
1217 |
FatalException(env->isolate(), try_catch); |
||
1218 |
return Local<Value>(); |
||
1219 |
} |
||
1220 |
} |
||
1221 |
|||
1222 |
6276 |
Local<Value> ret = callback->Call(recv, argc, argv); |
|
1223 |
|||
1224 |
✗✓✗✗ ✗✓ |
6258 |
if (ran_init_callback && !post_fn.IsEmpty()) { |
1225 |
Local<Value> did_throw = Boolean::New(env->isolate(), ret.IsEmpty()); |
||
1226 |
// Currently there's no way to retrieve an uid from node::MakeCallback(). |
||
1227 |
// This needs to be fixed. |
||
1228 |
Local<Value> vals[] = |
||
1229 |
{ Undefined(env->isolate()).As<Value>(), did_throw }; |
||
1230 |
TryCatch try_catch(env->isolate()); |
||
1231 |
MaybeLocal<Value> ar = |
||
1232 |
post_fn->Call(env->context(), object, arraysize(vals), vals); |
||
1233 |
if (ar.IsEmpty()) { |
||
1234 |
ClearFatalExceptionHandlers(env); |
||
1235 |
FatalException(env->isolate(), try_catch); |
||
1236 |
return Local<Value>(); |
||
1237 |
} |
||
1238 |
} |
||
1239 |
|||
1240 |
✓✓ | 6258 |
if (ret.IsEmpty()) { |
1241 |
// NOTE: For backwards compatibility with public API we return Undefined() |
||
1242 |
// if the top level call threw. |
||
1243 |
1023 |
return callback_scope.in_makecallback() ? |
|
1244 |
✓✓ | 2042 |
ret : Undefined(env->isolate()).As<Value>(); |
1245 |
} |
||
1246 |
|||
1247 |
✓✓ | 5235 |
if (has_domain) { |
1248 |
20 |
Local<Value> exit_v = domain->Get(env->exit_string()); |
|
1249 |
✓✗ | 10 |
if (exit_v->IsFunction()) { |
1250 |
✗✓ | 30 |
if (exit_v.As<Function>()->Call(domain, 0, nullptr).IsEmpty()) { |
1251 |
FatalError("node::MakeCallback", |
||
1252 |
"domain exit callback threw, please report this"); |
||
1253 |
} |
||
1254 |
} |
||
1255 |
} |
||
1256 |
|||
1257 |
✓✓ | 5235 |
if (callback_scope.in_makecallback()) { |
1258 |
23 |
return ret; |
|
1259 |
} |
||
1260 |
|||
1261 |
5212 |
Environment::TickInfo* tick_info = env->tick_info(); |
|
1262 |
|||
1263 |
✓✓ | 5212 |
if (tick_info->length() == 0) { |
1264 |
3715 |
env->isolate()->RunMicrotasks(); |
|
1265 |
} |
||
1266 |
|||
1267 |
5212 |
Local<Object> process = env->process_object(); |
|
1268 |
|||
1269 |
✓✓ | 5212 |
if (tick_info->length() == 0) { |
1270 |
3709 |
tick_info->set_index(0); |
|
1271 |
3709 |
return ret; |
|
1272 |
} |
||
1273 |
|||
1274 |
✓✓ | 4509 |
if (env->tick_callback_function()->Call(process, 0, nullptr).IsEmpty()) { |
1275 |
3 |
return Undefined(env->isolate()); |
|
1276 |
} |
||
1277 |
|||
1278 |
1502 |
return ret; |
|
1279 |
} |
||
1280 |
|||
1281 |
|||
1282 |
6244 |
Local<Value> MakeCallback(Environment* env, |
|
1283 |
Local<Object> recv, |
||
1284 |
Local<String> symbol, |
||
1285 |
int argc, |
||
1286 |
Local<Value> argv[]) { |
||
1287 |
6244 |
Local<Value> cb_v = recv->Get(symbol); |
|
1288 |
✗✓ | 6244 |
CHECK(cb_v->IsFunction()); |
1289 |
12488 |
return MakeCallback(env, recv.As<Value>(), cb_v.As<Function>(), argc, argv); |
|
1290 |
} |
||
1291 |
|||
1292 |
|||
1293 |
3115 |
Local<Value> MakeCallback(Environment* env, |
|
1294 |
Local<Object> recv, |
||
1295 |
const char* method, |
||
1296 |
int argc, |
||
1297 |
Local<Value> argv[]) { |
||
1298 |
3115 |
Local<String> method_string = OneByteString(env->isolate(), method); |
|
1299 |
3115 |
return MakeCallback(env, recv, method_string, argc, argv); |
|
1300 |
} |
||
1301 |
|||
1302 |
|||
1303 |
5 |
Local<Value> MakeCallback(Isolate* isolate, |
|
1304 |
Local<Object> recv, |
||
1305 |
const char* method, |
||
1306 |
int argc, |
||
1307 |
Local<Value> argv[]) { |
||
1308 |
10 |
EscapableHandleScope handle_scope(isolate); |
|
1309 |
5 |
Local<String> method_string = OneByteString(isolate, method); |
|
1310 |
return handle_scope.Escape( |
||
1311 |
15 |
MakeCallback(isolate, recv, method_string, argc, argv)); |
|
1312 |
} |
||
1313 |
|||
1314 |
|||
1315 |
10 |
Local<Value> MakeCallback(Isolate* isolate, |
|
1316 |
Local<Object> recv, |
||
1317 |
Local<String> symbol, |
||
1318 |
int argc, |
||
1319 |
Local<Value> argv[]) { |
||
1320 |
20 |
EscapableHandleScope handle_scope(isolate); |
|
1321 |
20 |
Local<Value> callback_v = recv->Get(symbol); |
|
1322 |
✗✓ | 10 |
if (callback_v.IsEmpty()) return Local<Value>(); |
1323 |
✗✓ | 10 |
if (!callback_v->IsFunction()) return Local<Value>(); |
1324 |
10 |
Local<Function> callback = callback_v.As<Function>(); |
|
1325 |
10 |
return handle_scope.Escape(MakeCallback(isolate, recv, callback, argc, argv)); |
|
1326 |
} |
||
1327 |
|||
1328 |
|||
1329 |
32 |
Local<Value> MakeCallback(Isolate* isolate, |
|
1330 |
Local<Object> recv, |
||
1331 |
Local<Function> callback, |
||
1332 |
int argc, |
||
1333 |
Local<Value> argv[]) { |
||
1334 |
// Observe the following two subtleties: |
||
1335 |
// |
||
1336 |
// 1. The environment is retrieved from the callback function's context. |
||
1337 |
// 2. The context to enter is retrieved from the environment. |
||
1338 |
// |
||
1339 |
// Because of the AssignToContext() call in src/node_contextify.cc, |
||
1340 |
// the two contexts need not be the same. |
||
1341 |
64 |
EscapableHandleScope handle_scope(isolate); |
|
1342 |
64 |
Environment* env = Environment::GetCurrent(callback->CreationContext()); |
|
1343 |
96 |
Context::Scope context_scope(env->context()); |
|
1344 |
return handle_scope.Escape( |
||
1345 |
96 |
MakeCallback(env, recv.As<Value>(), callback, argc, argv)); |
|
1346 |
} |
||
1347 |
|||
1348 |
|||
1349 |
54389 |
enum encoding ParseEncoding(const char* encoding, |
|
1350 |
enum encoding default_encoding) { |
||
1351 |
✓✓✓✓ ✓ |
54389 |
switch (encoding[0]) { |
1352 |
case 'u': |
||
1353 |
// utf8, utf16le |
||
1354 |
✓✓✓✗ |
4627 |
if (encoding[1] == 't' && encoding[2] == 'f') { |
1355 |
// Skip `-` |
||
1356 |
✓✓ | 4436 |
encoding += encoding[3] == '-' ? 4 : 3; |
1357 |
✓✓✗✓ |
4436 |
if (encoding[0] == '8' && encoding[1] == '\0') |
1358 |
return UTF8; |
||
1359 |
✗✓ | 15 |
if (strncmp(encoding, "16le", 4) == 0) |
1360 |
return UCS2; |
||
1361 |
|||
1362 |
// ucs2 |
||
1363 |
✓✓✓✗ |
191 |
} else if (encoding[1] == 'c' && encoding[2] == 's') { |
1364 |
✓✗ | 190 |
encoding += encoding[3] == '-' ? 4 : 3; |
1365 |
✓✗✗✓ |
190 |
if (encoding[0] == '2' && encoding[1] == '\0') |
1366 |
return UCS2; |
||
1367 |
} |
||
1368 |
break; |
||
1369 |
case 'l': |
||
1370 |
// latin1 |
||
1371 |
✓✓ | 46787 |
if (encoding[1] == 'a') { |
1372 |
✗✓ | 46785 |
if (strncmp(encoding + 2, "tin1", 4) == 0) |
1373 |
return LATIN1; |
||
1374 |
} |
||
1375 |
break; |
||
1376 |
case 'b': |
||
1377 |
// binary |
||
1378 |
✓✓ | 450 |
if (encoding[1] == 'i') { |
1379 |
✗✓ | 30 |
if (strncmp(encoding + 2, "nary", 4) == 0) |
1380 |
return LATIN1; |
||
1381 |
|||
1382 |
// buffer |
||
1383 |
✓✓ | 420 |
} else if (encoding[1] == 'u') { |
1384 |
✗✓ | 395 |
if (strncmp(encoding + 2, "ffer", 4) == 0) |
1385 |
return BUFFER; |
||
1386 |
} |
||
1387 |
break; |
||
1388 |
case '\0': |
||
1389 |
return default_encoding; |
||
1390 |
default: |
||
1391 |
break; |
||
1392 |
} |
||
1393 |
|||
1394 |
✓✗ | 2552 |
if (StringEqualNoCase(encoding, "utf8")) { |
1395 |
return UTF8; |
||
1396 |
✓✓ | 2552 |
} else if (StringEqualNoCase(encoding, "utf-8")) { |
1397 |
return UTF8; |
||
1398 |
✓✓ | 2551 |
} else if (StringEqualNoCase(encoding, "ascii")) { |
1399 |
return ASCII; |
||
1400 |
✓✓ | 2504 |
} else if (StringEqualNoCase(encoding, "base64")) { |
1401 |
return BASE64; |
||
1402 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "ucs2")) { |
1403 |
return UCS2; |
||
1404 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "ucs-2")) { |
1405 |
return UCS2; |
||
1406 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "utf16le")) { |
1407 |
return UCS2; |
||
1408 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "utf-16le")) { |
1409 |
return UCS2; |
||
1410 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "latin1")) { |
1411 |
return LATIN1; |
||
1412 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "binary")) { |
1413 |
return LATIN1; // BINARY is a deprecated alias of LATIN1. |
||
1414 |
✓✗ | 2481 |
} else if (StringEqualNoCase(encoding, "buffer")) { |
1415 |
return BUFFER; |
||
1416 |
✓✓ | 2481 |
} else if (StringEqualNoCase(encoding, "hex")) { |
1417 |
return HEX; |
||
1418 |
} else { |
||
1419 |
5 |
return default_encoding; |
|
1420 |
} |
||
1421 |
} |
||
1422 |
|||
1423 |
|||
1424 |
56453 |
enum encoding ParseEncoding(Isolate* isolate, |
|
1425 |
Local<Value> encoding_v, |
||
1426 |
enum encoding default_encoding) { |
||
1427 |
✓✓ | 112906 |
if (!encoding_v->IsString()) |
1428 |
return default_encoding; |
||
1429 |
|||
1430 |
54389 |
node::Utf8Value encoding(isolate, encoding_v); |
|
1431 |
|||
1432 |
54389 |
return ParseEncoding(*encoding, default_encoding); |
|
1433 |
} |
||
1434 |
|||
1435 |
193 |
Local<Value> Encode(Isolate* isolate, |
|
1436 |
const char* buf, |
||
1437 |
size_t len, |
||
1438 |
enum encoding encoding) { |
||
1439 |
✗✓ | 193 |
CHECK_NE(encoding, UCS2); |
1440 |
193 |
return StringBytes::Encode(isolate, buf, len, encoding); |
|
1441 |
} |
||
1442 |
|||
1443 |
Local<Value> Encode(Isolate* isolate, const uint16_t* buf, size_t len) { |
||
1444 |
return StringBytes::Encode(isolate, buf, len); |
||
1445 |
} |
||
1446 |
|||
1447 |
// Returns -1 if the handle was not valid for decoding |
||
1448 |
ssize_t DecodeBytes(Isolate* isolate, |
||
1449 |
Local<Value> val, |
||
1450 |
enum encoding encoding) { |
||
1451 |
HandleScope scope(isolate); |
||
1452 |
|||
1453 |
return StringBytes::Size(isolate, val, encoding); |
||
1454 |
} |
||
1455 |
|||
1456 |
// Returns number of bytes written. |
||
1457 |
ssize_t DecodeWrite(Isolate* isolate, |
||
1458 |
char* buf, |
||
1459 |
size_t buflen, |
||
1460 |
Local<Value> val, |
||
1461 |
enum encoding encoding) { |
||
1462 |
return StringBytes::Write(isolate, buf, buflen, val, encoding, nullptr); |
||
1463 |
} |
||
1464 |
|||
1465 |
360 |
bool IsExceptionDecorated(Environment* env, Local<Value> er) { |
|
1466 |
✓✗✗✓ ✓✗ |
360 |
if (!er.IsEmpty() && er->IsObject()) { |
1467 |
360 |
Local<Object> err_obj = er.As<Object>(); |
|
1468 |
auto maybe_value = |
||
1469 |
720 |
err_obj->GetPrivate(env->context(), env->decorated_private_symbol()); |
|
1470 |
360 |
Local<Value> decorated; |
|
1471 |
✓✗✓✓ |
360 |
return maybe_value.ToLocal(&decorated) && decorated->IsTrue(); |
1472 |
} |
||
1473 |
return false; |
||
1474 |
} |
||
1475 |
|||
1476 |
360 |
void AppendExceptionLine(Environment* env, |
|
1477 |
Local<Value> er, |
||
1478 |
Local<Message> message, |
||
1479 |
enum ErrorHandlingMode mode) { |
||
1480 |
✓✗ | 360 |
if (message.IsEmpty()) |
1481 |
27 |
return; |
|
1482 |
|||
1483 |
693 |
HandleScope scope(env->isolate()); |
|
1484 |
360 |
Local<Object> err_obj; |
|
1485 |
✓✗✗✓ ✓✗ |
360 |
if (!er.IsEmpty() && er->IsObject()) { |
1486 |
360 |
err_obj = er.As<Object>(); |
|
1487 |
|||
1488 |
360 |
auto context = env->context(); |
|
1489 |
360 |
auto processed_private_symbol = env->processed_private_symbol(); |
|
1490 |
// Do it only once per message |
||
1491 |
✓✓ | 720 |
if (err_obj->HasPrivate(context, processed_private_symbol).FromJust()) |
1492 |
15 |
return; |
|
1493 |
err_obj->SetPrivate( |
||
1494 |
context, |
||
1495 |
processed_private_symbol, |
||
1496 |
1035 |
True(env->isolate())); |
|
1497 |
} |
||
1498 |
|||
1499 |
// Print (filename):(line number): (message). |
||
1500 |
678 |
node::Utf8Value filename(env->isolate(), message->GetScriptResourceName()); |
|
1501 |
345 |
const char* filename_string = *filename; |
|
1502 |
345 |
int linenum = message->GetLineNumber(); |
|
1503 |
// Print line of source code. |
||
1504 |
1023 |
node::Utf8Value sourceline(env->isolate(), message->GetSourceLine()); |
|
1505 |
345 |
const char* sourceline_string = *sourceline; |
|
1506 |
|||
1507 |
// Because of how node modules work, all scripts are wrapped with a |
||
1508 |
// "function (module, exports, __filename, ...) {" |
||
1509 |
// to provide script local variables. |
||
1510 |
// |
||
1511 |
// When reporting errors on the first line of a script, this wrapper |
||
1512 |
// function is leaked to the user. There used to be a hack here to |
||
1513 |
// truncate off the first 62 characters, but it caused numerous other |
||
1514 |
// problems when vm.runIn*Context() methods were used for non-module |
||
1515 |
// code. |
||
1516 |
// |
||
1517 |
// If we ever decide to re-instate such a hack, the following steps |
||
1518 |
// must be taken: |
||
1519 |
// |
||
1520 |
// 1. Pass a flag around to say "this code was wrapped" |
||
1521 |
// 2. Update the stack frame output so that it is also correct. |
||
1522 |
// |
||
1523 |
// It would probably be simpler to add a line rather than add some |
||
1524 |
// number of characters to the first line, since V8 truncates the |
||
1525 |
// sourceline to 78 characters, and we end up not providing very much |
||
1526 |
// useful debugging info to the user if we remove 62 characters. |
||
1527 |
|||
1528 |
1035 |
int start = message->GetStartColumn(env->context()).FromMaybe(0); |
|
1529 |
1035 |
int end = message->GetEndColumn(env->context()).FromMaybe(0); |
|
1530 |
|||
1531 |
char arrow[1024]; |
||
1532 |
345 |
int max_off = sizeof(arrow) - 2; |
|
1533 |
|||
1534 |
int off = snprintf(arrow, |
||
1535 |
sizeof(arrow), |
||
1536 |
"%s:%i\n%s\n", |
||
1537 |
filename_string, |
||
1538 |
linenum, |
||
1539 |
345 |
sourceline_string); |
|
1540 |
✗✓ | 345 |
CHECK_GE(off, 0); |
1541 |
✓✓ | 345 |
if (off > max_off) { |
1542 |
138 |
off = max_off; |
|
1543 |
} |
||
1544 |
|||
1545 |
// Print wavy underline (GetUnderline is deprecated). |
||
1546 |
✓✓ | 12981 |
for (int i = 0; i < start; i++) { |
1547 |
✗✓✓✓ |
6463 |
if (sourceline_string[i] == '\0' || off >= max_off) { |
1548 |
break; |
||
1549 |
} |
||
1550 |
✗✓ | 6318 |
CHECK_LT(off, max_off); |
1551 |
✓✗ | 6318 |
arrow[off++] = (sourceline_string[i] == '\t') ? '\t' : ' '; |
1552 |
} |
||
1553 |
✓✓ | 1603 |
for (int i = start; i < end; i++) { |
1554 |
✓✓✓✓ |
793 |
if (sourceline_string[i] == '\0' || off >= max_off) { |
1555 |
break; |
||
1556 |
} |
||
1557 |
✗✓ | 629 |
CHECK_LT(off, max_off); |
1558 |
629 |
arrow[off++] = '^'; |
|
1559 |
} |
||
1560 |
✗✓ | 345 |
CHECK_LE(off, max_off); |
1561 |
345 |
arrow[off] = '\n'; |
|
1562 |
345 |
arrow[off + 1] = '\0'; |
|
1563 |
|||
1564 |
345 |
Local<String> arrow_str = String::NewFromUtf8(env->isolate(), arrow); |
|
1565 |
|||
1566 |
✓✗✗✓ |
345 |
const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty(); |
1567 |
// If allocating arrow_str failed, print it out. There's not much else to do. |
||
1568 |
// If it's not an error, but something needs to be printed out because |
||
1569 |
// it's a fatal exception, also print it out from here. |
||
1570 |
// Otherwise, the arrow property will be attached to the object and handled |
||
1571 |
// by the caller. |
||
1572 |
✓✗✓✓ ✓✓✓✓ |
345 |
if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) { |
1573 |
✓✗ | 12 |
if (env->printed_error()) |
1574 |
12 |
return; |
|
1575 |
12 |
env->set_printed_error(true); |
|
1576 |
|||
1577 |
12 |
uv_tty_reset_mode(); |
|
1578 |
12 |
PrintErrorString("\n%s", arrow); |
|
1579 |
12 |
return; |
|
1580 |
} |
||
1581 |
|||
1582 |
✗✓ | 1665 |
CHECK(err_obj->SetPrivate( |
1583 |
env->context(), |
||
1584 |
env->arrow_message_private_symbol(), |
||
1585 |
arrow_str).FromMaybe(false)); |
||
1586 |
} |
||
1587 |
|||
1588 |
|||
1589 |
59 |
static void ReportException(Environment* env, |
|
1590 |
Local<Value> er, |
||
1591 |
Local<Message> message) { |
||
1592 |
118 |
HandleScope scope(env->isolate()); |
|
1593 |
|||
1594 |
59 |
AppendExceptionLine(env, er, message, FATAL_ERROR); |
|
1595 |
|||
1596 |
59 |
Local<Value> trace_value; |
|
1597 |
59 |
Local<Value> arrow; |
|
1598 |
59 |
const bool decorated = IsExceptionDecorated(env, er); |
|
1599 |
|||
1600 |
✓✗✗✓ ✗✓ |
177 |
if (er->IsUndefined() || er->IsNull()) { |
1601 |
trace_value = Undefined(env->isolate()); |
||
1602 |
} else { |
||
1603 |
59 |
Local<Object> err_obj = er->ToObject(env->isolate()); |
|
1604 |
|||
1605 |
118 |
trace_value = err_obj->Get(env->stack_string()); |
|
1606 |
arrow = |
||
1607 |
59 |
err_obj->GetPrivate( |
|
1608 |
env->context(), |
||
1609 |
118 |
env->arrow_message_private_symbol()).ToLocalChecked(); |
|
1610 |
} |
||
1611 |
|||
1612 |
118 |
node::Utf8Value trace(env->isolate(), trace_value); |
|
1613 |
|||
1614 |
// range errors have a trace member set to undefined |
||
1615 |
✓✗✓✓ ✓✓ |
118 |
if (trace.length() > 0 && !trace_value->IsUndefined()) { |
1616 |
✓✗✓✓ ✓✓✓✓ |
116 |
if (arrow.IsEmpty() || !arrow->IsString() || decorated) { |
1617 |
26 |
PrintErrorString("%s\n", *trace); |
|
1618 |
} else { |
||
1619 |
64 |
node::Utf8Value arrow_string(env->isolate(), arrow); |
|
1620 |
32 |
PrintErrorString("%s\n%s\n", *arrow_string, *trace); |
|
1621 |
} |
||
1622 |
} else { |
||
1623 |
// this really only happens for RangeErrors, since they're the only |
||
1624 |
// kind that won't have all this info in the trace, or when non-Error |
||
1625 |
// objects are thrown manually. |
||
1626 |
1 |
Local<Value> message; |
|
1627 |
1 |
Local<Value> name; |
|
1628 |
|||
1629 |
✓✗ | 1 |
if (er->IsObject()) { |
1630 |
1 |
Local<Object> err_obj = er.As<Object>(); |
|
1631 |
2 |
message = err_obj->Get(env->message_string()); |
|
1632 |
2 |
name = err_obj->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "name")); |
|
1633 |
} |
||
1634 |
|||
1635 |
✗✓✓✗ |
3 |
if (message.IsEmpty() || |
1636 |
✗✗ | 2 |
message->IsUndefined() || |
1637 |
✓✗✗✗ |
1 |
name.IsEmpty() || |
1638 |
name->IsUndefined()) { |
||
1639 |
// Not an error object. Just print as-is. |
||
1640 |
2 |
String::Utf8Value message(er); |
|
1641 |
|||
1642 |
✗✓ | 1 |
PrintErrorString("%s\n", *message ? *message : |
1643 |
1 |
"<toString() threw exception>"); |
|
1644 |
} else { |
||
1645 |
node::Utf8Value name_string(env->isolate(), name); |
||
1646 |
node::Utf8Value message_string(env->isolate(), message); |
||
1647 |
|||
1648 |
if (arrow.IsEmpty() || !arrow->IsString() || decorated) { |
||
1649 |
PrintErrorString("%s: %s\n", *name_string, *message_string); |
||
1650 |
} else { |
||
1651 |
node::Utf8Value arrow_string(env->isolate(), arrow); |
||
1652 |
PrintErrorString("%s\n%s: %s\n", |
||
1653 |
*arrow_string, |
||
1654 |
*name_string, |
||
1655 |
*message_string); |
||
1656 |
} |
||
1657 |
} |
||
1658 |
} |
||
1659 |
|||
1660 |
59 |
fflush(stderr); |
|
1661 |
59 |
} |
|
1662 |
|||
1663 |
|||
1664 |
2 |
static void ReportException(Environment* env, const TryCatch& try_catch) { |
|
1665 |
2 |
ReportException(env, try_catch.Exception(), try_catch.Message()); |
|
1666 |
2 |
} |
|
1667 |
|||
1668 |
|||
1669 |
// Executes a str within the current v8 context. |
||
1670 |
1750 |
static Local<Value> ExecuteString(Environment* env, |
|
1671 |
Local<String> source, |
||
1672 |
Local<String> filename) { |
||
1673 |
3500 |
EscapableHandleScope scope(env->isolate()); |
|
1674 |
3500 |
TryCatch try_catch(env->isolate()); |
|
1675 |
|||
1676 |
// try_catch must be nonverbose to disable FatalException() handler, |
||
1677 |
// we will handle exceptions ourself. |
||
1678 |
1750 |
try_catch.SetVerbose(false); |
|
1679 |
|||
1680 |
5250 |
ScriptOrigin origin(filename); |
|
1681 |
MaybeLocal<v8::Script> script = |
||
1682 |
1750 |
v8::Script::Compile(env->context(), source, &origin); |
|
1683 |
✗✓ | 1750 |
if (script.IsEmpty()) { |
1684 |
ReportException(env, try_catch); |
||
1685 |
exit(3); |
||
1686 |
} |
||
1687 |
|||
1688 |
1750 |
Local<Value> result = script.ToLocalChecked()->Run(); |
|
1689 |
✗✓ | 1750 |
if (result.IsEmpty()) { |
1690 |
ReportException(env, try_catch); |
||
1691 |
exit(4); |
||
1692 |
} |
||
1693 |
|||
1694 |
3500 |
return scope.Escape(result); |
|
1695 |
} |
||
1696 |
|||
1697 |
|||
1698 |
1 |
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) { |
|
1699 |
1 |
Environment* env = Environment::GetCurrent(args); |
|
1700 |
|||
1701 |
1 |
Local<Array> ary = Array::New(args.GetIsolate()); |
|
1702 |
1 |
Local<Context> ctx = env->context(); |
|
1703 |
1 |
Local<Function> fn = env->push_values_to_array_function(); |
|
1704 |
✓✓ | 17 |
Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; |
1705 |
1 |
size_t idx = 0; |
|
1706 |
|||
1707 |
✓✓ | 15 |
for (auto w : *env->req_wrap_queue()) { |
1708 |
✓✗ | 24 |
if (w->persistent().IsEmpty()) |
1709 |
continue; |
||
1710 |
36 |
argv[idx] = w->object(); |
|
1711 |
✓✓ | 12 |
if (++idx >= arraysize(argv)) { |
1712 |
3 |
fn->Call(ctx, ary, idx, argv).ToLocalChecked(); |
|
1713 |
1 |
idx = 0; |
|
1714 |
} |
||
1715 |
} |
||
1716 |
|||
1717 |
✓✗ | 1 |
if (idx > 0) { |
1718 |
3 |
fn->Call(ctx, ary, idx, argv).ToLocalChecked(); |
|
1719 |
} |
||
1720 |
|||
1721 |
2 |
args.GetReturnValue().Set(ary); |
|
1722 |
1 |
} |
|
1723 |
|||
1724 |
|||
1725 |
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but |
||
1726 |
// implemented here for consistency with GetActiveRequests(). |
||
1727 |
3 |
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) { |
|
1728 |
3 |
Environment* env = Environment::GetCurrent(args); |
|
1729 |
|||
1730 |
3 |
Local<Array> ary = Array::New(env->isolate()); |
|
1731 |
3 |
Local<Context> ctx = env->context(); |
|
1732 |
3 |
Local<Function> fn = env->push_values_to_array_function(); |
|
1733 |
✓✓ | 51 |
Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; |
1734 |
3 |
size_t idx = 0; |
|
1735 |
|||
1736 |
3 |
Local<String> owner_sym = env->owner_string(); |
|
1737 |
|||
1738 |
✓✓ | 29 |
for (auto w : *env->handle_wrap_queue()) { |
1739 |
✓✗✗✓ ✓✗ |
40 |
if (w->persistent().IsEmpty() || !HandleWrap::HasRef(w)) |
1740 |
continue; |
||
1741 |
40 |
Local<Object> object = w->object(); |
|
1742 |
20 |
Local<Value> owner = object->Get(owner_sym); |
|
1743 |
✓✓ | 40 |
if (owner->IsUndefined()) |
1744 |
3 |
owner = object; |
|
1745 |
20 |
argv[idx] = owner; |
|
1746 |
✓✓ | 20 |
if (++idx >= arraysize(argv)) { |
1747 |
6 |
fn->Call(ctx, ary, idx, argv).ToLocalChecked(); |
|
1748 |
2 |
idx = 0; |
|
1749 |
} |
||
1750 |
} |
||
1751 |
✓✓ | 3 |
if (idx > 0) { |
1752 |
6 |
fn->Call(ctx, ary, idx, argv).ToLocalChecked(); |
|
1753 |
} |
||
1754 |
|||
1755 |
6 |
args.GetReturnValue().Set(ary); |
|
1756 |
3 |
} |
|
1757 |
|||
1758 |
|||
1759 |
NO_RETURN void Abort() { |
||
1760 |
DumpBacktrace(stderr); |
||
1761 |
fflush(stderr); |
||
1762 |
ABORT_NO_BACKTRACE(); |
||
1763 |
} |
||
1764 |
|||
1765 |
|||
1766 |
NO_RETURN void Assert(const char* const (*args)[4]) { |
||
1767 |
auto filename = (*args)[0]; |
||
1768 |
auto linenum = (*args)[1]; |
||
1769 |
auto message = (*args)[2]; |
||
1770 |
auto function = (*args)[3]; |
||
1771 |
|||
1772 |
char exepath[256]; |
||
1773 |
size_t exepath_size = sizeof(exepath); |
||
1774 |
if (uv_exepath(exepath, &exepath_size)) |
||
1775 |
snprintf(exepath, sizeof(exepath), "node"); |
||
1776 |
|||
1777 |
char pid[12] = {0}; |
||
1778 |
#ifndef _WIN32 |
||
1779 |
snprintf(pid, sizeof(pid), "[%u]", getpid()); |
||
1780 |
#endif |
||
1781 |
|||
1782 |
fprintf(stderr, "%s%s: %s:%s:%s%s Assertion `%s' failed.\n", |
||
1783 |
exepath, pid, filename, linenum, |
||
1784 |
function, *function ? ":" : "", message); |
||
1785 |
fflush(stderr); |
||
1786 |
|||
1787 |
Abort(); |
||
1788 |
} |
||
1789 |
|||
1790 |
|||
1791 |
static void Abort(const FunctionCallbackInfo<Value>& args) { |
||
1792 |
Abort(); |
||
1793 |
} |
||
1794 |
|||
1795 |
|||
1796 |
46 |
static void Chdir(const FunctionCallbackInfo<Value>& args) { |
|
1797 |
46 |
Environment* env = Environment::GetCurrent(args); |
|
1798 |
|||
1799 |
✓✓✓✓ ✓✓ |
180 |
if (args.Length() != 1 || !args[0]->IsString()) { |
1800 |
3 |
return env->ThrowTypeError("Bad argument."); |
|
1801 |
} |
||
1802 |
|||
1803 |
129 |
node::Utf8Value path(args.GetIsolate(), args[0]); |
|
1804 |
43 |
int err = uv_chdir(*path); |
|
1805 |
✗✓ | 43 |
if (err) { |
1806 |
return env->ThrowUVException(err, "uv_chdir"); |
||
1807 |
} |
||
1808 |
} |
||
1809 |
|||
1810 |
|||
1811 |
2132 |
static void Cwd(const FunctionCallbackInfo<Value>& args) { |
|
1812 |
2132 |
Environment* env = Environment::GetCurrent(args); |
|
1813 |
#ifdef _WIN32 |
||
1814 |
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */ |
||
1815 |
char buf[MAX_PATH * 4]; |
||
1816 |
#else |
||
1817 |
char buf[PATH_MAX]; |
||
1818 |
#endif |
||
1819 |
|||
1820 |
2132 |
size_t cwd_len = sizeof(buf); |
|
1821 |
2132 |
int err = uv_cwd(buf, &cwd_len); |
|
1822 |
✓✓ | 2132 |
if (err) { |
1823 |
4 |
return env->ThrowUVException(err, "uv_cwd"); |
|
1824 |
} |
||
1825 |
|||
1826 |
Local<String> cwd = String::NewFromUtf8(env->isolate(), |
||
1827 |
buf, |
||
1828 |
String::kNormalString, |
||
1829 |
2128 |
cwd_len); |
|
1830 |
4256 |
args.GetReturnValue().Set(cwd); |
|
1831 |
} |
||
1832 |
|||
1833 |
|||
1834 |
138 |
static void Umask(const FunctionCallbackInfo<Value>& args) { |
|
1835 |
138 |
Environment* env = Environment::GetCurrent(args); |
|
1836 |
uint32_t old; |
||
1837 |
|||
1838 |
✓✓✗✓ ✓✓ |
282 |
if (args.Length() < 1 || args[0]->IsUndefined()) { |
1839 |
135 |
old = umask(0); |
|
1840 |
135 |
umask(static_cast<mode_t>(old)); |
|
1841 |
✓✓✓✗ ✗✓ |
8 |
} else if (!args[0]->IsInt32() && !args[0]->IsString()) { |
1842 |
return env->ThrowTypeError("argument must be an integer or octal string."); |
||
1843 |
} else { |
||
1844 |
int oct; |
||
1845 |
✓✓ | 3 |
if (args[0]->IsInt32()) { |
1846 |
2 |
oct = args[0]->Uint32Value(); |
|
1847 |
} else { |
||
1848 |
1 |
oct = 0; |
|
1849 |
2 |
node::Utf8Value str(env->isolate(), args[0]); |
|
1850 |
|||
1851 |
// Parse the octal string. |
||
1852 |
✓✓ | 5 |
for (size_t i = 0; i < str.length(); i++) { |
1853 |
4 |
char c = (*str)[i]; |
|
1854 |
✗✓ | 4 |
if (c > '7' || c < '0') { |
1855 |
return env->ThrowTypeError("invalid octal string"); |
||
1856 |
} |
||
1857 |
4 |
oct *= 8; |
|
1858 |
4 |
oct += c - '0'; |
|
1859 |
} |
||
1860 |
} |
||
1861 |
3 |
old = umask(static_cast<mode_t>(oct)); |
|
1862 |
} |
||
1863 |
|||
1864 |
138 |
args.GetReturnValue().Set(old); |
|
1865 |
} |
||
1866 |
|||
1867 |
|||
1868 |
#if defined(__POSIX__) && !defined(__ANDROID__) |
||
1869 |
|||
1870 |
static const uid_t uid_not_found = static_cast<uid_t>(-1); |
||
1871 |
static const gid_t gid_not_found = static_cast<gid_t>(-1); |
||
1872 |
|||
1873 |
|||
1874 |
static uid_t uid_by_name(const char* name) { |
||
1875 |
struct passwd pwd; |
||
1876 |
struct passwd* pp; |
||
1877 |
char buf[8192]; |
||
1878 |
|||
1879 |
errno = 0; |
||
1880 |
pp = nullptr; |
||
1881 |
|||
1882 |
if (getpwnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr) { |
||
1883 |
return pp->pw_uid; |
||
1884 |
} |
||
1885 |
|||
1886 |
return uid_not_found; |
||
1887 |
} |
||
1888 |
|||
1889 |
|||
1890 |
static char* name_by_uid(uid_t uid) { |
||
1891 |
struct passwd pwd; |
||
1892 |
struct passwd* pp; |
||
1893 |
char buf[8192]; |
||
1894 |
int rc; |
||
1895 |
|||
1896 |
errno = 0; |
||
1897 |
pp = nullptr; |
||
1898 |
|||
1899 |
if ((rc = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pp)) == 0 && |
||
1900 |
pp != nullptr) { |
||
1901 |
return strdup(pp->pw_name); |
||
1902 |
} |
||
1903 |
|||
1904 |
if (rc == 0) { |
||
1905 |
errno = ENOENT; |
||
1906 |
} |
||
1907 |
|||
1908 |
return nullptr; |
||
1909 |
} |
||
1910 |
|||
1911 |
|||
1912 |
static gid_t gid_by_name(const char* name) { |
||
1913 |
struct group pwd; |
||
1914 |
struct group* pp; |
||
1915 |
char buf[8192]; |
||
1916 |
|||
1917 |
errno = 0; |
||
1918 |
pp = nullptr; |
||
1919 |
|||
1920 |
if (getgrnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr) { |
||
1921 |
return pp->gr_gid; |
||
1922 |
} |
||
1923 |
|||
1924 |
return gid_not_found; |
||
1925 |
} |
||
1926 |
|||
1927 |
|||
1928 |
#if 0 // For future use. |
||
1929 |
static const char* name_by_gid(gid_t gid) { |
||
1930 |
struct group pwd; |
||
1931 |
struct group* pp; |
||
1932 |
char buf[8192]; |
||
1933 |
int rc; |
||
1934 |
|||
1935 |
errno = 0; |
||
1936 |
pp = nullptr; |
||
1937 |
|||
1938 |
if ((rc = getgrgid_r(gid, &pwd, buf, sizeof(buf), &pp)) == 0 && |
||
1939 |
pp != nullptr) { |
||
1940 |
return strdup(pp->gr_name); |
||
1941 |
} |
||
1942 |
|||
1943 |
if (rc == 0) { |
||
1944 |
errno = ENOENT; |
||
1945 |
} |
||
1946 |
|||
1947 |
return nullptr; |
||
1948 |
} |
||
1949 |
#endif |
||
1950 |
|||
1951 |
|||
1952 |
static uid_t uid_by_name(Isolate* isolate, Local<Value> value) { |
||
1953 |
if (value->IsUint32()) { |
||
1954 |
return static_cast<uid_t>(value->Uint32Value()); |
||
1955 |
} else { |
||
1956 |
node::Utf8Value name(isolate, value); |
||
1957 |
return uid_by_name(*name); |
||
1958 |
} |
||
1959 |
} |
||
1960 |
|||
1961 |
|||
1962 |
static gid_t gid_by_name(Isolate* isolate, Local<Value> value) { |
||
1963 |
if (value->IsUint32()) { |
||
1964 |
return static_cast<gid_t>(value->Uint32Value()); |
||
1965 |
} else { |
||
1966 |
node::Utf8Value name(isolate, value); |
||
1967 |
return gid_by_name(*name); |
||
1968 |
} |
||
1969 |
} |
||
1970 |
|||
1971 |
18 |
static void GetUid(const FunctionCallbackInfo<Value>& args) { |
|
1972 |
// uid_t is an uint32_t on all supported platforms. |
||
1973 |
54 |
args.GetReturnValue().Set(static_cast<uint32_t>(getuid())); |
|
1974 |
18 |
} |
|
1975 |
|||
1976 |
|||
1977 |
7 |
static void GetGid(const FunctionCallbackInfo<Value>& args) { |
|
1978 |
// gid_t is an uint32_t on all supported platforms. |
||
1979 |
21 |
args.GetReturnValue().Set(static_cast<uint32_t>(getgid())); |
|
1980 |
7 |
} |
|
1981 |
|||
1982 |
|||
1983 |
static void GetEUid(const FunctionCallbackInfo<Value>& args) { |
||
1984 |
// uid_t is an uint32_t on all supported platforms. |
||
1985 |
args.GetReturnValue().Set(static_cast<uint32_t>(geteuid())); |
||
1986 |
} |
||
1987 |
|||
1988 |
|||
1989 |
static void GetEGid(const FunctionCallbackInfo<Value>& args) { |
||
1990 |
// gid_t is an uint32_t on all supported platforms. |
||
1991 |
args.GetReturnValue().Set(static_cast<uint32_t>(getegid())); |
||
1992 |
} |
||
1993 |
|||
1994 |
|||
1995 |
static void SetGid(const FunctionCallbackInfo<Value>& args) { |
||
1996 |
Environment* env = Environment::GetCurrent(args); |
||
1997 |
|||
1998 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
||
1999 |
return env->ThrowTypeError("setgid argument must be a number or a string"); |
||
2000 |
} |
||
2001 |
|||
2002 |
gid_t gid = gid_by_name(env->isolate(), args[0]); |
||
2003 |
|||
2004 |
if (gid == gid_not_found) { |
||
2005 |
return env->ThrowError("setgid group id does not exist"); |
||
2006 |
} |
||
2007 |
|||
2008 |
if (setgid(gid)) { |
||
2009 |
return env->ThrowErrnoException(errno, "setgid"); |
||
2010 |
} |
||
2011 |
} |
||
2012 |
|||
2013 |
|||
2014 |
static void SetEGid(const FunctionCallbackInfo<Value>& args) { |
||
2015 |
Environment* env = Environment::GetCurrent(args); |
||
2016 |
|||
2017 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
||
2018 |
return env->ThrowTypeError("setegid argument must be a number or string"); |
||
2019 |
} |
||
2020 |
|||
2021 |
gid_t gid = gid_by_name(env->isolate(), args[0]); |
||
2022 |
|||
2023 |
if (gid == gid_not_found) { |
||
2024 |
return env->ThrowError("setegid group id does not exist"); |
||
2025 |
} |
||
2026 |
|||
2027 |
if (setegid(gid)) { |
||
2028 |
return env->ThrowErrnoException(errno, "setegid"); |
||
2029 |
} |
||
2030 |
} |
||
2031 |
|||
2032 |
|||
2033 |
static void SetUid(const FunctionCallbackInfo<Value>& args) { |
||
2034 |
Environment* env = Environment::GetCurrent(args); |
||
2035 |
|||
2036 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
||
2037 |
return env->ThrowTypeError("setuid argument must be a number or a string"); |
||
2038 |
} |
||
2039 |
|||
2040 |
uid_t uid = uid_by_name(env->isolate(), args[0]); |
||
2041 |
|||
2042 |
if (uid == uid_not_found) { |
||
2043 |
return env->ThrowError("setuid user id does not exist"); |
||
2044 |
} |
||
2045 |
|||
2046 |
if (setuid(uid)) { |
||
2047 |
return env->ThrowErrnoException(errno, "setuid"); |
||
2048 |
} |
||
2049 |
} |
||
2050 |
|||
2051 |
|||
2052 |
static void SetEUid(const FunctionCallbackInfo<Value>& args) { |
||
2053 |
Environment* env = Environment::GetCurrent(args); |
||
2054 |
|||
2055 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
||
2056 |
return env->ThrowTypeError("seteuid argument must be a number or string"); |
||
2057 |
} |
||
2058 |
|||
2059 |
uid_t uid = uid_by_name(env->isolate(), args[0]); |
||
2060 |
|||
2061 |
if (uid == uid_not_found) { |
||
2062 |
return env->ThrowError("seteuid user id does not exist"); |
||
2063 |
} |
||
2064 |
|||
2065 |
if (seteuid(uid)) { |
||
2066 |
return env->ThrowErrnoException(errno, "seteuid"); |
||
2067 |
} |
||
2068 |
} |
||
2069 |
|||
2070 |
|||
2071 |
1 |
static void GetGroups(const FunctionCallbackInfo<Value>& args) { |
|
2072 |
1 |
Environment* env = Environment::GetCurrent(args); |
|
2073 |
|||
2074 |
1 |
int ngroups = getgroups(0, nullptr); |
|
2075 |
|||
2076 |
✗✓ | 1 |
if (ngroups == -1) { |
2077 |
return env->ThrowErrnoException(errno, "getgroups"); |
||
2078 |
} |
||
2079 |
|||
2080 |
✓✗ | 1 |
gid_t* groups = new gid_t[ngroups]; |
2081 |
|||
2082 |
1 |
ngroups = getgroups(ngroups, groups); |
|
2083 |
|||
2084 |
✗✓ | 1 |
if (ngroups == -1) { |
2085 |
delete[] groups; |
||
2086 |
return env->ThrowErrnoException(errno, "getgroups"); |
||
2087 |
} |
||
2088 |
|||
2089 |
1 |
Local<Array> groups_list = Array::New(env->isolate(), ngroups); |
|
2090 |
1 |
bool seen_egid = false; |
|
2091 |
1 |
gid_t egid = getegid(); |
|
2092 |
|||
2093 |
✓✓ | 2 |
for (int i = 0; i < ngroups; i++) { |
2094 |
2 |
groups_list->Set(i, Integer::New(env->isolate(), groups[i])); |
|
2095 |
✓✗ | 1 |
if (groups[i] == egid) |
2096 |
1 |
seen_egid = true; |
|
2097 |
} |
||
2098 |
|||
2099 |
✓✗ | 1 |
delete[] groups; |
2100 |
|||
2101 |
✗✓ | 1 |
if (seen_egid == false) { |
2102 |
groups_list->Set(ngroups, Integer::New(env->isolate(), egid)); |
||
2103 |
} |
||
2104 |
|||
2105 |
1 |
args.GetReturnValue().Set(groups_list); |
|
2106 |
} |
||
2107 |
|||
2108 |
|||
2109 |
static void SetGroups(const FunctionCallbackInfo<Value>& args) { |
||
2110 |
Environment* env = Environment::GetCurrent(args); |
||
2111 |
|||
2112 |
if (!args[0]->IsArray()) { |
||
2113 |
return env->ThrowTypeError("argument 1 must be an array"); |
||
2114 |
} |
||
2115 |
|||
2116 |
Local<Array> groups_list = args[0].As<Array>(); |
||
2117 |
size_t size = groups_list->Length(); |
||
2118 |
gid_t* groups = new gid_t[size]; |
||
2119 |
|||
2120 |
for (size_t i = 0; i < size; i++) { |
||
2121 |
gid_t gid = gid_by_name(env->isolate(), groups_list->Get(i)); |
||
2122 |
|||
2123 |
if (gid == gid_not_found) { |
||
2124 |
delete[] groups; |
||
2125 |
return env->ThrowError("group name not found"); |
||
2126 |
} |
||
2127 |
|||
2128 |
groups[i] = gid; |
||
2129 |
} |
||
2130 |
|||
2131 |
int rc = setgroups(size, groups); |
||
2132 |
delete[] groups; |
||
2133 |
|||
2134 |
if (rc == -1) { |
||
2135 |
return env->ThrowErrnoException(errno, "setgroups"); |
||
2136 |
} |
||
2137 |
} |
||
2138 |
|||
2139 |
|||
2140 |
static void InitGroups(const FunctionCallbackInfo<Value>& args) { |
||
2141 |
Environment* env = Environment::GetCurrent(args); |
||
2142 |
|||
2143 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
||
2144 |
return env->ThrowTypeError("argument 1 must be a number or a string"); |
||
2145 |
} |
||
2146 |
|||
2147 |
if (!args[1]->IsUint32() && !args[1]->IsString()) { |
||
2148 |
return env->ThrowTypeError("argument 2 must be a number or a string"); |
||
2149 |
} |
||
2150 |
|||
2151 |
node::Utf8Value arg0(env->isolate(), args[0]); |
||
2152 |
gid_t extra_group; |
||
2153 |
bool must_free; |
||
2154 |
char* user; |
||
2155 |
|||
2156 |
if (args[0]->IsUint32()) { |
||
2157 |
user = name_by_uid(args[0]->Uint32Value()); |
||
2158 |
must_free = true; |
||
2159 |
} else { |
||
2160 |
user = *arg0; |
||
2161 |
must_free = false; |
||
2162 |
} |
||
2163 |
|||
2164 |
if (user == nullptr) { |
||
2165 |
return env->ThrowError("initgroups user not found"); |
||
2166 |
} |
||
2167 |
|||
2168 |
extra_group = gid_by_name(env->isolate(), args[1]); |
||
2169 |
|||
2170 |
if (extra_group == gid_not_found) { |
||
2171 |
if (must_free) |
||
2172 |
free(user); |
||
2173 |
return env->ThrowError("initgroups extra group not found"); |
||
2174 |
} |
||
2175 |
|||
2176 |
int rc = initgroups(user, extra_group); |
||
2177 |
|||
2178 |
if (must_free) { |
||
2179 |
free(user); |
||
2180 |
} |
||
2181 |
|||
2182 |
if (rc) { |
||
2183 |
return env->ThrowErrnoException(errno, "initgroups"); |
||
2184 |
} |
||
2185 |
} |
||
2186 |
|||
2187 |
#endif // __POSIX__ && !defined(__ANDROID__) |
||
2188 |
|||
2189 |
|||
2190 |
1686 |
static void WaitForInspectorDisconnect(Environment* env) { |
|
2191 |
#if HAVE_INSPECTOR |
||
2192 |
✗✓ | 1686 |
if (env->inspector_agent()->IsConnected()) { |
2193 |
// Restore signal dispositions, the app is done and is no longer |
||
2194 |
// capable of handling signals. |
||
2195 |
#ifdef __POSIX__ |
||
2196 |
struct sigaction act; |
||
2197 |
memset(&act, 0, sizeof(act)); |
||
2198 |
for (unsigned nr = 1; nr < kMaxSignal; nr += 1) { |
||
2199 |
if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF) |
||
2200 |
continue; |
||
2201 |
act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL; |
||
2202 |
CHECK_EQ(0, sigaction(nr, &act, nullptr)); |
||
2203 |
} |
||
2204 |
#endif |
||
2205 |
env->inspector_agent()->WaitForDisconnect(); |
||
2206 |
} |
||
2207 |
#endif |
||
2208 |
1686 |
} |
|
2209 |
|||
2210 |
|||
2211 |
141 |
void Exit(const FunctionCallbackInfo<Value>& args) { |
|
2212 |
141 |
WaitForInspectorDisconnect(Environment::GetCurrent(args)); |
|
2213 |
141 |
exit(args[0]->Int32Value()); |
|
2214 |
} |
||
2215 |
|||
2216 |
|||
2217 |
static void Uptime(const FunctionCallbackInfo<Value>& args) { |
||
2218 |
Environment* env = Environment::GetCurrent(args); |
||
2219 |
double uptime; |
||
2220 |
|||
2221 |
uv_update_time(env->event_loop()); |
||
2222 |
uptime = uv_now(env->event_loop()) - prog_start_time; |
||
2223 |
|||
2224 |
args.GetReturnValue().Set(Number::New(env->isolate(), uptime / 1000)); |
||
2225 |
} |
||
2226 |
|||
2227 |
|||
2228 |
2 |
void MemoryUsage(const FunctionCallbackInfo<Value>& args) { |
|
2229 |
2 |
Environment* env = Environment::GetCurrent(args); |
|
2230 |
|||
2231 |
size_t rss; |
||
2232 |
2 |
int err = uv_resident_set_memory(&rss); |
|
2233 |
✗✓ | 2 |
if (err) { |
2234 |
return env->ThrowUVException(err, "uv_resident_set_memory"); |
||
2235 |
} |
||
2236 |
|||
2237 |
// V8 memory usage |
||
2238 |
2 |
HeapStatistics v8_heap_stats; |
|
2239 |
2 |
env->isolate()->GetHeapStatistics(&v8_heap_stats); |
|
2240 |
|||
2241 |
Local<Number> heap_total = |
||
2242 |
2 |
Number::New(env->isolate(), v8_heap_stats.total_heap_size()); |
|
2243 |
Local<Number> heap_used = |
||
2244 |
2 |
Number::New(env->isolate(), v8_heap_stats.used_heap_size()); |
|
2245 |
Local<Number> external_mem = |
||
2246 |
Number::New(env->isolate(), |
||
2247 |
4 |
env->isolate()->AdjustAmountOfExternalAllocatedMemory(0)); |
|
2248 |
|||
2249 |
2 |
Local<Object> info = Object::New(env->isolate()); |
|
2250 |
8 |
info->Set(env->rss_string(), Number::New(env->isolate(), rss)); |
|
2251 |
6 |
info->Set(env->heap_total_string(), heap_total); |
|
2252 |
6 |
info->Set(env->heap_used_string(), heap_used); |
|
2253 |
6 |
info->Set(env->external_string(), external_mem); |
|
2254 |
|||
2255 |
4 |
args.GetReturnValue().Set(info); |
|
2256 |
} |
||
2257 |
|||
2258 |
|||
2259 |
44 |
void Kill(const FunctionCallbackInfo<Value>& args) { |
|
2260 |
44 |
Environment* env = Environment::GetCurrent(args); |
|
2261 |
|||
2262 |
✗✓ | 44 |
if (args.Length() != 2) { |
2263 |
return env->ThrowError("Bad argument."); |
||
2264 |
} |
||
2265 |
|||
2266 |
44 |
int pid = args[0]->Int32Value(); |
|
2267 |
44 |
int sig = args[1]->Int32Value(); |
|
2268 |
44 |
int err = uv_kill(pid, sig); |
|
2269 |
88 |
args.GetReturnValue().Set(err); |
|
2270 |
} |
||
2271 |
|||
2272 |
// used in Hrtime() below |
||
2273 |
#define NANOS_PER_SEC 1000000000 |
||
2274 |
|||
2275 |
// Hrtime exposes libuv's uv_hrtime() high-resolution timer. |
||
2276 |
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds, |
||
2277 |
// so this function instead returns an Array with 2 entries representing seconds |
||
2278 |
// and nanoseconds, to avoid any integer overflow possibility. |
||
2279 |
// Pass in an Array from a previous hrtime() call to instead get a time diff. |
||
2280 |
20 |
void Hrtime(const FunctionCallbackInfo<Value>& args) { |
|
2281 |
20 |
uint64_t t = uv_hrtime(); |
|
2282 |
|||
2283 |
40 |
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer(); |
|
2284 |
20 |
uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data()); |
|
2285 |
|||
2286 |
// These three indices will contain the values for the hrtime tuple. The |
||
2287 |
// seconds value is broken into the upper/lower 32 bits and stored in two |
||
2288 |
// uint32 fields to be converted back in JS. |
||
2289 |
20 |
fields[0] = (t / NANOS_PER_SEC) >> 32; |
|
2290 |
20 |
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff; |
|
2291 |
20 |
fields[2] = t % NANOS_PER_SEC; |
|
2292 |
20 |
} |
|
2293 |
|||
2294 |
// Microseconds in a second, as a float, used in CPUUsage() below |
||
2295 |
#define MICROS_PER_SEC 1e6 |
||
2296 |
|||
2297 |
// CPUUsage use libuv's uv_getrusage() this-process resource usage accessor, |
||
2298 |
// to access ru_utime (user CPU time used) and ru_stime (system CPU time used), |
||
2299 |
// which are uv_timeval_t structs (long tv_sec, long tv_usec). |
||
2300 |
// Returns those values as Float64 microseconds in the elements of the array |
||
2301 |
// passed to the function. |
||
2302 |
33 |
void CPUUsage(const FunctionCallbackInfo<Value>& args) { |
|
2303 |
uv_rusage_t rusage; |
||
2304 |
|||
2305 |
// Call libuv to get the values we'll return. |
||
2306 |
33 |
int err = uv_getrusage(&rusage); |
|
2307 |
✗✓ | 33 |
if (err) { |
2308 |
// On error, return the strerror version of the error code. |
||
2309 |
Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err)); |
||
2310 |
args.GetReturnValue().Set(errmsg); |
||
2311 |
return; |
||
2312 |
} |
||
2313 |
|||
2314 |
// Get the double array pointer from the Float64Array argument. |
||
2315 |
✗✓ | 33 |
CHECK(args[0]->IsFloat64Array()); |
2316 |
66 |
Local<Float64Array> array = args[0].As<Float64Array>(); |
|
2317 |
✗✓ | 33 |
CHECK_EQ(array->Length(), 2); |
2318 |
33 |
Local<ArrayBuffer> ab = array->Buffer(); |
|
2319 |
33 |
double* fields = static_cast<double*>(ab->GetContents().Data()); |
|
2320 |
|||
2321 |
// Set the Float64Array elements to be user / system values in microseconds. |
||
2322 |
33 |
fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec; |
|
2323 |
33 |
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec; |
|
2324 |
} |
||
2325 |
|||
2326 |
47471 |
extern "C" void node_module_register(void* m) { |
|
2327 |
47471 |
struct node_module* mp = reinterpret_cast<struct node_module*>(m); |
|
2328 |
|||
2329 |
✓✓ | 47471 |
if (mp->nm_flags & NM_F_BUILTIN) { |
2330 |
47439 |
mp->nm_link = modlist_builtin; |
|
2331 |
47439 |
modlist_builtin = mp; |
|
2332 |
✗✓ | 32 |
} else if (!node_is_initialized) { |
2333 |
// "Linked" modules are included as part of the node project. |
||
2334 |
// Like builtins they are registered *before* node::Init runs. |
||
2335 |
mp->nm_flags = NM_F_LINKED; |
||
2336 |
mp->nm_link = modlist_linked; |
||
2337 |
modlist_linked = mp; |
||
2338 |
} else { |
||
2339 |
32 |
modpending = mp; |
|
2340 |
} |
||
2341 |
47471 |
} |
|
2342 |
|||
2343 |
37176 |
struct node_module* get_builtin_module(const char* name) { |
|
2344 |
struct node_module* mp; |
||
2345 |
|||
2346 |
✓✓ | 544098 |
for (mp = modlist_builtin; mp != nullptr; mp = mp->nm_link) { |
2347 |
✓✓ | 540597 |
if (strcmp(mp->nm_modname, name) == 0) |
2348 |
break; |
||
2349 |
} |
||
2350 |
|||
2351 |
✓✓✗✓ |
37176 |
CHECK(mp == nullptr || (mp->nm_flags & NM_F_BUILTIN) != 0); |
2352 |
37176 |
return (mp); |
|
2353 |
} |
||
2354 |
|||
2355 |
struct node_module* get_linked_module(const char* name) { |
||
2356 |
struct node_module* mp; |
||
2357 |
|||
2358 |
for (mp = modlist_linked; mp != nullptr; mp = mp->nm_link) { |
||
2359 |
if (strcmp(mp->nm_modname, name) == 0) |
||
2360 |
break; |
||
2361 |
} |
||
2362 |
|||
2363 |
CHECK(mp == nullptr || (mp->nm_flags & NM_F_LINKED) != 0); |
||
2364 |
return mp; |
||
2365 |
} |
||
2366 |
|||
2367 |
typedef void (UV_DYNAMIC* extInit)(Local<Object> exports); |
||
2368 |
|||
2369 |
// DLOpen is process.dlopen(module, filename). |
||
2370 |
// Used to load 'module.node' dynamically shared objects. |
||
2371 |
// |
||
2372 |
// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict |
||
2373 |
// when two contexts try to load the same shared object. Maybe have a shadow |
||
2374 |
// cache that's a plain C list or hash table that's shared across contexts? |
||
2375 |
35 |
void DLOpen(const FunctionCallbackInfo<Value>& args) { |
|
2376 |
35 |
Environment* env = Environment::GetCurrent(args); |
|
2377 |
uv_lib_t lib; |
||
2378 |
|||
2379 |
✗✓ | 35 |
CHECK_EQ(modpending, nullptr); |
2380 |
|||
2381 |
✗✓ | 35 |
if (args.Length() != 2) { |
2382 |
env->ThrowError("process.dlopen takes exactly 2 arguments."); |
||
2383 |
4 |
return; |
|
2384 |
} |
||
2385 |
|||
2386 |
70 |
Local<Object> module = args[0]->ToObject(env->isolate()); // Cast |
|
2387 |
66 |
node::Utf8Value filename(env->isolate(), args[1]); // Cast |
|
2388 |
35 |
const bool is_dlopen_error = uv_dlopen(*filename, &lib); |
|
2389 |
|||
2390 |
// Objects containing v14 or later modules will have registered themselves |
||
2391 |
// on the pending list. Activate all of them now. At present, only one |
||
2392 |
// module per object is supported. |
||
2393 |
35 |
node_module* const mp = modpending; |
|
2394 |
35 |
modpending = nullptr; |
|
2395 |
|||
2396 |
✓✓ | 35 |
if (is_dlopen_error) { |
2397 |
3 |
Local<String> errmsg = OneByteString(env->isolate(), uv_dlerror(&lib)); |
|
2398 |
3 |
uv_dlclose(&lib); |
|
2399 |
#ifdef _WIN32 |
||
2400 |
// Windows needs to add the filename into the error message |
||
2401 |
errmsg = String::Concat(errmsg, args[1]->ToString(env->isolate())); |
||
2402 |
#endif // _WIN32 |
||
2403 |
3 |
env->isolate()->ThrowException(Exception::Error(errmsg)); |
|
2404 |
return; |
||
2405 |
} |
||
2406 |
|||
2407 |
✗✓ | 32 |
if (mp == nullptr) { |
2408 |
uv_dlclose(&lib); |
||
2409 |
env->ThrowError("Module did not self-register."); |
||
2410 |
return; |
||
2411 |
} |
||
2412 |
✓✓ | 32 |
if (mp->nm_version != NODE_MODULE_VERSION) { |
2413 |
char errmsg[1024]; |
||
2414 |
1 |
snprintf(errmsg, |
|
2415 |
sizeof(errmsg), |
||
2416 |
"The module '%s'" |
||
2417 |
"\nwas compiled against a different Node.js version using" |
||
2418 |
"\nNODE_MODULE_VERSION %d. This version of Node.js requires" |
||
2419 |
"\nNODE_MODULE_VERSION %d. Please try re-compiling or " |
||
2420 |
"re-installing\nthe module (for instance, using `npm rebuild` or" |
||
2421 |
"`npm install`).", |
||
2422 |
1 |
*filename, mp->nm_version, NODE_MODULE_VERSION); |
|
2423 |
|||
2424 |
// NOTE: `mp` is allocated inside of the shared library's memory, calling |
||
2425 |
// `uv_dlclose` will deallocate it |
||
2426 |
1 |
uv_dlclose(&lib); |
|
2427 |
1 |
env->ThrowError(errmsg); |
|
2428 |
return; |
||
2429 |
} |
||
2430 |
✗✓ | 31 |
if (mp->nm_flags & NM_F_BUILTIN) { |
2431 |
uv_dlclose(&lib); |
||
2432 |
env->ThrowError("Built-in module self-registered."); |
||
2433 |
return; |
||
2434 |
} |
||
2435 |
|||
2436 |
31 |
mp->nm_dso_handle = lib.handle; |
|
2437 |
31 |
mp->nm_link = modlist_addon; |
|
2438 |
31 |
modlist_addon = mp; |
|
2439 |
|||
2440 |
31 |
Local<String> exports_string = env->exports_string(); |
|
2441 |
124 |
Local<Object> exports = module->Get(exports_string)->ToObject(env->isolate()); |
|
2442 |
|||
2443 |
✓✓ | 31 |
if (mp->nm_context_register_func != nullptr) { |
2444 |
6 |
mp->nm_context_register_func(exports, module, env->context(), mp->nm_priv); |
|
2445 |
✓✗ | 29 |
} else if (mp->nm_register_func != nullptr) { |
2446 |
58 |
mp->nm_register_func(exports, module, mp->nm_priv); |
|
2447 |
} else { |
||
2448 |
uv_dlclose(&lib); |
||
2449 |
env->ThrowError("Module has no declared entry point."); |
||
2450 |
return; |
||
2451 |
} |
||
2452 |
|||
2453 |
// Tell coverity that 'handle' should not be freed when we return. |
||
2454 |
// coverity[leaked_storage] |
||
2455 |
} |
||
2456 |
|||
2457 |
|||
2458 |
static void OnFatalError(const char* location, const char* message) { |
||
2459 |
if (location) { |
||
2460 |
PrintErrorString("FATAL ERROR: %s %s\n", location, message); |
||
2461 |
} else { |
||
2462 |
PrintErrorString("FATAL ERROR: %s\n", message); |
||
2463 |
} |
||
2464 |
fflush(stderr); |
||
2465 |
ABORT(); |
||
2466 |
} |
||
2467 |
|||
2468 |
|||
2469 |
NO_RETURN void FatalError(const char* location, const char* message) { |
||
2470 |
OnFatalError(location, message); |
||
2471 |
// to suppress compiler warning |
||
2472 |
ABORT(); |
||
2473 |
} |
||
2474 |
|||
2475 |
|||
2476 |
1175 |
void FatalException(Isolate* isolate, |
|
2477 |
Local<Value> error, |
||
2478 |
Local<Message> message) { |
||
2479 |
2288 |
HandleScope scope(isolate); |
|
2480 |
|||
2481 |
1175 |
Environment* env = Environment::GetCurrent(isolate); |
|
2482 |
1175 |
Local<Object> process_object = env->process_object(); |
|
2483 |
1175 |
Local<String> fatal_exception_string = env->fatal_exception_string(); |
|
2484 |
Local<Function> fatal_exception_function = |
||
2485 |
2350 |
process_object->Get(fatal_exception_string).As<Function>(); |
|
2486 |
|||
2487 |
1175 |
int exit_code = 0; |
|
2488 |
✗✓ | 1175 |
if (!fatal_exception_function->IsFunction()) { |
2489 |
// failed before the process._fatalException function was added! |
||
2490 |
// this is probably pretty bad. Nothing to do but report and exit. |
||
2491 |
ReportException(env, error, message); |
||
2492 |
exit_code = 6; |
||
2493 |
} |
||
2494 |
|||
2495 |
✓✗ | 1175 |
if (exit_code == 0) { |
2496 |
2347 |
TryCatch fatal_try_catch(isolate); |
|
2497 |
|||
2498 |
// Do not call FatalException when _fatalException handler throws |
||
2499 |
1175 |
fatal_try_catch.SetVerbose(false); |
|
2500 |
|||
2501 |
// this will return true if the JS layer handled it, false otherwise |
||
2502 |
Local<Value> caught = |
||
2503 |
1175 |
fatal_exception_function->Call(process_object, 1, &error); |
|
2504 |
|||
2505 |
✓✓ | 1172 |
if (fatal_try_catch.HasCaught()) { |
2506 |
// the fatal exception function threw, so we must exit |
||
2507 |
2 |
ReportException(env, fatal_try_catch); |
|
2508 |
2 |
exit_code = 7; |
|
2509 |
} |
||
2510 |
|||
2511 |
✓✓✓✓ ✓✓ |
2342 |
if (exit_code == 0 && false == caught->BooleanValue()) { |
2512 |
57 |
ReportException(env, error, message); |
|
2513 |
57 |
exit_code = 1; |
|
2514 |
} |
||
2515 |
} |
||
2516 |
|||
2517 |
✓✓ | 1172 |
if (exit_code) { |
2518 |
#if HAVE_INSPECTOR |
||
2519 |
✗✓ | 59 |
if (debug_options.inspector_enabled()) { |
2520 |
env->inspector_agent()->FatalException(error, message); |
||
2521 |
} |
||
2522 |
#endif |
||
2523 |
59 |
exit(exit_code); |
|
2524 |
} |
||
2525 |
1113 |
} |
|
2526 |
|||
2527 |
|||
2528 |
4 |
void FatalException(Isolate* isolate, const TryCatch& try_catch) { |
|
2529 |
4 |
HandleScope scope(isolate); |
|
2530 |
// TODO(bajtos) do not call FatalException if try_catch is verbose |
||
2531 |
// (requires V8 API to expose getter for try_catch.is_verbose_) |
||
2532 |
4 |
FatalException(isolate, try_catch.Exception(), try_catch.Message()); |
|
2533 |
} |
||
2534 |
|||
2535 |
|||
2536 |
1171 |
void OnMessage(Local<Message> message, Local<Value> error) { |
|
2537 |
// The current version of V8 sends messages for errors only |
||
2538 |
// (thus `error` is always set). |
||
2539 |
1171 |
FatalException(Isolate::GetCurrent(), error, message); |
|
2540 |
1113 |
} |
|
2541 |
|||
2542 |
|||
2543 |
4 |
void ClearFatalExceptionHandlers(Environment* env) { |
|
2544 |
4 |
Local<Object> process = env->process_object(); |
|
2545 |
Local<Value> events = |
||
2546 |
16 |
process->Get(env->context(), env->events_string()).ToLocalChecked(); |
|
2547 |
|||
2548 |
✓✗ | 4 |
if (events->IsObject()) { |
2549 |
12 |
events.As<Object>()->Set( |
|
2550 |
env->context(), |
||
2551 |
OneByteString(env->isolate(), "uncaughtException"), |
||
2552 |
32 |
Undefined(env->isolate())).FromJust(); |
|
2553 |
} |
||
2554 |
|||
2555 |
8 |
process->Set( |
|
2556 |
env->context(), |
||
2557 |
env->domain_string(), |
||
2558 |
32 |
Undefined(env->isolate())).FromJust(); |
|
2559 |
4 |
} |
|
2560 |
|||
2561 |
// Call process.emitWarning(str), fmt is a snprintf() format string |
||
2562 |
1 |
void ProcessEmitWarning(Environment* env, const char* fmt, ...) { |
|
2563 |
char warning[1024]; |
||
2564 |
va_list ap; |
||
2565 |
|||
2566 |
1 |
va_start(ap, fmt); |
|
2567 |
1 |
vsnprintf(warning, sizeof(warning), fmt, ap); |
|
2568 |
1 |
va_end(ap); |
|
2569 |
|||
2570 |
2 |
HandleScope handle_scope(env->isolate()); |
|
2571 |
3 |
Context::Scope context_scope(env->context()); |
|
2572 |
|||
2573 |
1 |
Local<Object> process = env->process_object(); |
|
2574 |
MaybeLocal<Value> emit_warning = process->Get(env->context(), |
||
2575 |
3 |
FIXED_ONE_BYTE_STRING(env->isolate(), "emitWarning")); |
|
2576 |
2 |
Local<Value> arg = node::OneByteString(env->isolate(), warning); |
|
2577 |
|||
2578 |
1 |
Local<Value> f; |
|
2579 |
|||
2580 |
✓✗ | 1 |
if (!emit_warning.ToLocal(&f)) return; |
2581 |
✓✗ | 1 |
if (!f->IsFunction()) return; |
2582 |
|||
2583 |
// MakeCallback() unneeded, because emitWarning is internal code, it calls |
||
2584 |
// process.emit('warning', ..), but does so on the nextTick. |
||
2585 |
2 |
f.As<v8::Function>()->Call(process, 1, &arg); |
|
2586 |
} |
||
2587 |
|||
2588 |
|||
2589 |
98142 |
static void Binding(const FunctionCallbackInfo<Value>& args) { |
|
2590 |
98142 |
Environment* env = Environment::GetCurrent(args); |
|
2591 |
|||
2592 |
196284 |
Local<String> module = args[0]->ToString(env->isolate()); |
|
2593 |
133567 |
node::Utf8Value module_v(env->isolate(), module); |
|
2594 |
|||
2595 |
98142 |
Local<Object> cache = env->binding_cache_object(); |
|
2596 |
98142 |
Local<Object> exports; |
|
2597 |
|||
2598 |
✓✓ | 294426 |
if (cache->Has(env->context(), module).FromJust()) { |
2599 |
188148 |
exports = cache->Get(module)->ToObject(env->isolate()); |
|
2600 |
62716 |
args.GetReturnValue().Set(exports); |
|
2601 |
62717 |
return; |
|
2602 |
} |
||
2603 |
|||
2604 |
// Append a string to process.moduleLoadList |
||
2605 |
char buf[1024]; |
||
2606 |
70852 |
snprintf(buf, sizeof(buf), "Binding %s", *module_v); |
|
2607 |
|||
2608 |
35426 |
Local<Array> modules = env->module_load_list_array(); |
|
2609 |
35426 |
uint32_t l = modules->Length(); |
|
2610 |
70852 |
modules->Set(l, OneByteString(env->isolate(), buf)); |
|
2611 |
|||
2612 |
35426 |
node_module* mod = get_builtin_module(*module_v); |
|
2613 |
✓✓ | 35426 |
if (mod != nullptr) { |
2614 |
31925 |
exports = Object::New(env->isolate()); |
|
2615 |
// Internal bindings don't have a "module" object, only exports. |
||
2616 |
✗✓ | 31925 |
CHECK_EQ(mod->nm_register_func, nullptr); |
2617 |
✗✓ | 31925 |
CHECK_NE(mod->nm_context_register_func, nullptr); |
2618 |
95775 |
Local<Value> unused = Undefined(env->isolate()); |
|
2619 |
63850 |
mod->nm_context_register_func(exports, unused, |
|
2620 |
31925 |
env->context(), mod->nm_priv); |
|
2621 |
63850 |
cache->Set(module, exports); |
|
2622 |
✓✓ | 3501 |
} else if (!strcmp(*module_v, "constants")) { |
2623 |
1750 |
exports = Object::New(env->isolate()); |
|
2624 |
1750 |
DefineConstants(env->isolate(), exports); |
|
2625 |
3500 |
cache->Set(module, exports); |
|
2626 |
✓✓ | 1751 |
} else if (!strcmp(*module_v, "natives")) { |
2627 |
1750 |
exports = Object::New(env->isolate()); |
|
2628 |
1750 |
DefineJavaScript(env, exports); |
|
2629 |
3500 |
cache->Set(module, exports); |
|
2630 |
} else { |
||
2631 |
char errmsg[1024]; |
||
2632 |
1 |
snprintf(errmsg, |
|
2633 |
sizeof(errmsg), |
||
2634 |
"No such module: %s", |
||
2635 |
1 |
*module_v); |
|
2636 |
1 |
return env->ThrowError(errmsg); |
|
2637 |
} |
||
2638 |
|||
2639 |
70850 |
args.GetReturnValue().Set(exports); |
|
2640 |
} |
||
2641 |
|||
2642 |
static void LinkedBinding(const FunctionCallbackInfo<Value>& args) { |
||
2643 |
Environment* env = Environment::GetCurrent(args.GetIsolate()); |
||
2644 |
|||
2645 |
Local<String> module_name = args[0]->ToString(env->isolate()); |
||
2646 |
|||
2647 |
Local<Object> cache = env->binding_cache_object(); |
||
2648 |
Local<Value> exports_v = cache->Get(module_name); |
||
2649 |
|||
2650 |
if (exports_v->IsObject()) |
||
2651 |
return args.GetReturnValue().Set(exports_v.As<Object>()); |
||
2652 |
|||
2653 |
node::Utf8Value module_name_v(env->isolate(), module_name); |
||
2654 |
node_module* mod = get_linked_module(*module_name_v); |
||
2655 |
|||
2656 |
if (mod == nullptr) { |
||
2657 |
char errmsg[1024]; |
||
2658 |
snprintf(errmsg, |
||
2659 |
sizeof(errmsg), |
||
2660 |
"No such module was linked: %s", |
||
2661 |
*module_name_v); |
||
2662 |
return env->ThrowError(errmsg); |
||
2663 |
} |
||
2664 |
|||
2665 |
Local<Object> module = Object::New(env->isolate()); |
||
2666 |
Local<Object> exports = Object::New(env->isolate()); |
||
2667 |
Local<String> exports_prop = String::NewFromUtf8(env->isolate(), "exports"); |
||
2668 |
module->Set(exports_prop, exports); |
||
2669 |
|||
2670 |
if (mod->nm_context_register_func != nullptr) { |
||
2671 |
mod->nm_context_register_func(exports, |
||
2672 |
module, |
||
2673 |
env->context(), |
||
2674 |
mod->nm_priv); |
||
2675 |
} else if (mod->nm_register_func != nullptr) { |
||
2676 |
mod->nm_register_func(exports, module, mod->nm_priv); |
||
2677 |
} else { |
||
2678 |
return env->ThrowError("Linked module has no declared entry point."); |
||
2679 |
} |
||
2680 |
|||
2681 |
auto effective_exports = module->Get(exports_prop); |
||
2682 |
cache->Set(module_name, effective_exports); |
||
2683 |
|||
2684 |
args.GetReturnValue().Set(effective_exports); |
||
2685 |
} |
||
2686 |
|||
2687 |
4 |
static void ProcessTitleGetter(Local<Name> property, |
|
2688 |
const PropertyCallbackInfo<Value>& info) { |
||
2689 |
char buffer[512]; |
||
2690 |
4 |
uv_get_process_title(buffer, sizeof(buffer)); |
|
2691 |
12 |
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), buffer)); |
|
2692 |
4 |
} |
|
2693 |
|||
2694 |
|||
2695 |
27 |
static void ProcessTitleSetter(Local<Name> property, |
|
2696 |
Local<Value> value, |
||
2697 |
const PropertyCallbackInfo<void>& info) { |
||
2698 |
54 |
node::Utf8Value title(info.GetIsolate(), value); |
|
2699 |
// TODO(piscisaureus): protect with a lock |
||
2700 |
27 |
uv_set_process_title(*title); |
|
2701 |
27 |
} |
|
2702 |
|||
2703 |
|||
2704 |
32757 |
static void EnvGetter(Local<Name> property, |
|
2705 |
const PropertyCallbackInfo<Value>& info) { |
||
2706 |
32757 |
Isolate* isolate = info.GetIsolate(); |
|
2707 |
✓✓ | 32757 |
if (property->IsSymbol()) { |
2708 |
19775 |
return info.GetReturnValue().SetUndefined(); |
|
2709 |
} |
||
2710 |
#ifdef __POSIX__ |
||
2711 |
45743 |
node::Utf8Value key(isolate, property); |
|
2712 |
32753 |
const char* val = getenv(*key); |
|
2713 |
✓✓ | 32753 |
if (val) { |
2714 |
59289 |
return info.GetReturnValue().Set(String::NewFromUtf8(isolate, val)); |
|
2715 |
} |
||
2716 |
#else // _WIN32 |
||
2717 |
node::TwoByteValue key(isolate, property); |
||
2718 |
WCHAR buffer[32767]; // The maximum size allowed for environment variables. |
||
2719 |
DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key), |
||
2720 |
buffer, |
||
2721 |
arraysize(buffer)); |
||
2722 |
// If result >= sizeof buffer the buffer was too small. That should never |
||
2723 |
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not |
||
2724 |
// not found. |
||
2725 |
if ((result > 0 || GetLastError() == ERROR_SUCCESS) && |
||
2726 |
result < arraysize(buffer)) { |
||
2727 |
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer); |
||
2728 |
Local<String> rc = String::NewFromTwoByte(isolate, two_byte_buffer); |
||
2729 |
return info.GetReturnValue().Set(rc); |
||
2730 |
} |
||
2731 |
#endif |
||
2732 |
} |
||
2733 |
|||
2734 |
|||
2735 |
98 |
static void EnvSetter(Local<Name> property, |
|
2736 |
Local<Value> value, |
||
2737 |
const PropertyCallbackInfo<Value>& info) { |
||
2738 |
#ifdef __POSIX__ |
||
2739 |
294 |
node::Utf8Value key(info.GetIsolate(), property); |
|
2740 |
196 |
node::Utf8Value val(info.GetIsolate(), value); |
|
2741 |
98 |
setenv(*key, *val, 1); |
|
2742 |
#else // _WIN32 |
||
2743 |
node::TwoByteValue key(info.GetIsolate(), property); |
||
2744 |
node::TwoByteValue val(info.GetIsolate(), value); |
||
2745 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key); |
||
2746 |
// Environment variables that start with '=' are read-only. |
||
2747 |
if (key_ptr[0] != L'=') { |
||
2748 |
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val)); |
||
2749 |
} |
||
2750 |
#endif |
||
2751 |
// Whether it worked or not, always return value. |
||
2752 |
196 |
info.GetReturnValue().Set(value); |
|
2753 |
98 |
} |
|
2754 |
|||
2755 |
|||
2756 |
11254 |
static void EnvQuery(Local<Name> property, |
|
2757 |
const PropertyCallbackInfo<Integer>& info) { |
||
2758 |
11254 |
int32_t rc = -1; // Not found unless proven otherwise. |
|
2759 |
#ifdef __POSIX__ |
||
2760 |
33762 |
node::Utf8Value key(info.GetIsolate(), property); |
|
2761 |
✓✓ | 11254 |
if (getenv(*key)) |
2762 |
10753 |
rc = 0; |
|
2763 |
#else // _WIN32 |
||
2764 |
node::TwoByteValue key(info.GetIsolate(), property); |
||
2765 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key); |
||
2766 |
if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 || |
||
2767 |
GetLastError() == ERROR_SUCCESS) { |
||
2768 |
rc = 0; |
||
2769 |
if (key_ptr[0] == L'=') { |
||
2770 |
// Environment variables that start with '=' are hidden and read-only. |
||
2771 |
rc = static_cast<int32_t>(v8::ReadOnly) | |
||
2772 |
static_cast<int32_t>(v8::DontDelete) | |
||
2773 |
static_cast<int32_t>(v8::DontEnum); |
||
2774 |
} |
||
2775 |
} |
||
2776 |
#endif |
||
2777 |
✓✓ | 11254 |
if (rc != -1) |
2778 |
21506 |
info.GetReturnValue().Set(rc); |
|
2779 |
11254 |
} |
|
2780 |
|||
2781 |
|||
2782 |
282 |
static void EnvDeleter(Local<Name> property, |
|
2783 |
const PropertyCallbackInfo<Boolean>& info) { |
||
2784 |
#ifdef __POSIX__ |
||
2785 |
846 |
node::Utf8Value key(info.GetIsolate(), property); |
|
2786 |
282 |
unsetenv(*key); |
|
2787 |
#else |
||
2788 |
node::TwoByteValue key(info.GetIsolate(), property); |
||
2789 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key); |
||
2790 |
SetEnvironmentVariableW(key_ptr, nullptr); |
||
2791 |
#endif |
||
2792 |
|||
2793 |
// process.env never has non-configurable properties, so always |
||
2794 |
// return true like the tc39 delete operator. |
||
2795 |
564 |
info.GetReturnValue().Set(true); |
|
2796 |
282 |
} |
|
2797 |
|||
2798 |
|||
2799 |
908 |
static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) { |
|
2800 |
908 |
Environment* env = Environment::GetCurrent(info); |
|
2801 |
908 |
Isolate* isolate = env->isolate(); |
|
2802 |
908 |
Local<Context> ctx = env->context(); |
|
2803 |
908 |
Local<Function> fn = env->push_values_to_array_function(); |
|
2804 |
✓✓ | 15436 |
Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; |
2805 |
size_t idx = 0; |
||
2806 |
|||
2807 |
#ifdef __POSIX__ |
||
2808 |
int size = 0; |
||
2809 |
✓✓ | 27032 |
while (environ[size]) |
2810 |
13062 |
size++; |
|
2811 |
|||
2812 |
908 |
Local<Array> envarr = Array::New(isolate); |
|
2813 |
|||
2814 |
✓✓ | 13970 |
for (int i = 0; i < size; ++i) { |
2815 |
13062 |
const char* var = environ[i]; |
|
2816 |
13062 |
const char* s = strchr(var, '='); |
|
2817 |
✓✗ | 13062 |
const int length = s ? s - var : strlen(var); |
2818 |
argv[idx] = String::NewFromUtf8(isolate, |
||
2819 |
var, |
||
2820 |
String::kNormalString, |
||
2821 |
26124 |
length); |
|
2822 |
✓✓ | 13062 |
if (++idx >= arraysize(argv)) { |
2823 |
3060 |
fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); |
|
2824 |
1020 |
idx = 0; |
|
2825 |
} |
||
2826 |
} |
||
2827 |
✓✓ | 908 |
if (idx > 0) { |
2828 |
2538 |
fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); |
|
2829 |
} |
||
2830 |
#else // _WIN32 |
||
2831 |
WCHAR* environment = GetEnvironmentStringsW(); |
||
2832 |
if (environment == nullptr) |
||
2833 |
return; // This should not happen. |
||
2834 |
Local<Array> envarr = Array::New(isolate); |
||
2835 |
WCHAR* p = environment; |
||
2836 |
while (*p) { |
||
2837 |
WCHAR *s; |
||
2838 |
if (*p == L'=') { |
||
2839 |
// If the key starts with '=' it is a hidden environment variable. |
||
2840 |
p += wcslen(p) + 1; |
||
2841 |
continue; |
||
2842 |
} else { |
||
2843 |
s = wcschr(p, L'='); |
||
2844 |
} |
||
2845 |
if (!s) { |
||
2846 |
s = p + wcslen(p); |
||
2847 |
} |
||
2848 |
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p); |
||
2849 |
const size_t two_byte_buffer_len = s - p; |
||
2850 |
argv[idx] = String::NewFromTwoByte(isolate, |
||
2851 |
two_byte_buffer, |
||
2852 |
String::kNormalString, |
||
2853 |
two_byte_buffer_len); |
||
2854 |
if (++idx >= arraysize(argv)) { |
||
2855 |
fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); |
||
2856 |
idx = 0; |
||
2857 |
} |
||
2858 |
p = s + wcslen(s) + 1; |
||
2859 |
} |
||
2860 |
if (idx > 0) { |
||
2861 |
fn->Call(ctx, envarr, idx, argv).ToLocalChecked(); |
||
2862 |
} |
||
2863 |
FreeEnvironmentStringsW(environment); |
||
2864 |
#endif |
||
2865 |
|||
2866 |
1816 |
info.GetReturnValue().Set(envarr); |
|
2867 |
908 |
} |
|
2868 |
|||
2869 |
|||
2870 |
1750 |
static Local<Object> GetFeatures(Environment* env) { |
|
2871 |
3500 |
EscapableHandleScope scope(env->isolate()); |
|
2872 |
|||
2873 |
1750 |
Local<Object> obj = Object::New(env->isolate()); |
|
2874 |
#if defined(DEBUG) && DEBUG |
||
2875 |
Local<Value> debug = True(env->isolate()); |
||
2876 |
#else |
||
2877 |
5250 |
Local<Value> debug = False(env->isolate()); |
|
2878 |
#endif // defined(DEBUG) && DEBUG |
||
2879 |
|||
2880 |
3500 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "debug"), debug); |
|
2881 |
7000 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "uv"), True(env->isolate())); |
|
2882 |
// TODO(bnoordhuis) ping libuv |
||
2883 |
7000 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ipv6"), True(env->isolate())); |
|
2884 |
|||
2885 |
#ifdef OPENSSL_NPN_NEGOTIATED |
||
2886 |
3500 |
Local<Boolean> tls_npn = True(env->isolate()); |
|
2887 |
#else |
||
2888 |
Local<Boolean> tls_npn = False(env->isolate()); |
||
2889 |
#endif |
||
2890 |
3500 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_npn"), tls_npn); |
|
2891 |
|||
2892 |
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation |
||
2893 |
3500 |
Local<Boolean> tls_alpn = True(env->isolate()); |
|
2894 |
#else |
||
2895 |
Local<Boolean> tls_alpn = False(env->isolate()); |
||
2896 |
#endif |
||
2897 |
3500 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_alpn"), tls_alpn); |
|
2898 |
|||
2899 |
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB |
||
2900 |
3500 |
Local<Boolean> tls_sni = True(env->isolate()); |
|
2901 |
#else |
||
2902 |
Local<Boolean> tls_sni = False(env->isolate()); |
||
2903 |
#endif |
||
2904 |
3500 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_sni"), tls_sni); |
|
2905 |
|||
2906 |
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) |
||
2907 |
3500 |
Local<Boolean> tls_ocsp = True(env->isolate()); |
|
2908 |
#else |
||
2909 |
Local<Boolean> tls_ocsp = False(env->isolate()); |
||
2910 |
#endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) |
||
2911 |
3500 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_ocsp"), tls_ocsp); |
|
2912 |
|||
2913 |
8750 |
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls"), |
|
2914 |
Boolean::New(env->isolate(), |
||
2915 |
3500 |
get_builtin_module("crypto") != nullptr)); |
|
2916 |
|||
2917 |
3500 |
return scope.Escape(obj); |
|
2918 |
} |
||
2919 |
|||
2920 |
|||
2921 |
42 |
static void DebugPortGetter(Local<Name> property, |
|
2922 |
const PropertyCallbackInfo<Value>& info) { |
||
2923 |
126 |
info.GetReturnValue().Set(debug_options.port()); |
|
2924 |
42 |
} |
|
2925 |
|||
2926 |
|||
2927 |
static void DebugPortSetter(Local<Name> property, |
||
2928 |
Local<Value> value, |
||
2929 |
const PropertyCallbackInfo<void>& info) { |
||
2930 |
debug_options.set_port(value->Int32Value()); |
||
2931 |
} |
||
2932 |
|||
2933 |
|||
2934 |
static void DebugProcess(const FunctionCallbackInfo<Value>& args); |
||
2935 |
static void DebugPause(const FunctionCallbackInfo<Value>& args); |
||
2936 |
static void DebugEnd(const FunctionCallbackInfo<Value>& args); |
||
2937 |
|||
2938 |
|||
2939 |
5388 |
void NeedImmediateCallbackGetter(Local<Name> property, |
|
2940 |
const PropertyCallbackInfo<Value>& info) { |
||
2941 |
5388 |
Environment* env = Environment::GetCurrent(info); |
|
2942 |
5388 |
const uv_check_t* immediate_check_handle = env->immediate_check_handle(); |
|
2943 |
5388 |
bool active = uv_is_active( |
|
2944 |
5388 |
reinterpret_cast<const uv_handle_t*>(immediate_check_handle)); |
|
2945 |
16164 |
info.GetReturnValue().Set(active); |
|
2946 |
5388 |
} |
|
2947 |
|||
2948 |
|||
2949 |
3538 |
static void NeedImmediateCallbackSetter( |
|
2950 |
Local<Name> property, |
||
2951 |
Local<Value> value, |
||
2952 |
const PropertyCallbackInfo<void>& info) { |
||
2953 |
3538 |
Environment* env = Environment::GetCurrent(info); |
|
2954 |
|||
2955 |
3538 |
uv_check_t* immediate_check_handle = env->immediate_check_handle(); |
|
2956 |
3538 |
bool active = uv_is_active( |
|
2957 |
3538 |
reinterpret_cast<const uv_handle_t*>(immediate_check_handle)); |
|
2958 |
|||
2959 |
✓✓ | 3538 |
if (active == value->BooleanValue()) |
2960 |
return; |
||
2961 |
|||
2962 |
3515 |
uv_idle_t* immediate_idle_handle = env->immediate_idle_handle(); |
|
2963 |
|||
2964 |
✓✓ | 3515 |
if (active) { |
2965 |
1747 |
uv_check_stop(immediate_check_handle); |
|
2966 |
1747 |
uv_idle_stop(immediate_idle_handle); |
|
2967 |
} else { |
||
2968 |
1768 |
uv_check_start(immediate_check_handle, CheckImmediate); |
|
2969 |
// Idle handle is needed only to stop the event loop from blocking in poll. |
||
2970 |
1768 |
uv_idle_start(immediate_idle_handle, IdleImmediateDummy); |
|
2971 |
} |
||
2972 |
} |
||
2973 |
|||
2974 |
|||
2975 |
void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) { |
||
2976 |
Environment* env = Environment::GetCurrent(args); |
||
2977 |
env->StartProfilerIdleNotifier(); |
||
2978 |
} |
||
2979 |
|||
2980 |
|||
2981 |
void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) { |
||
2982 |
Environment* env = Environment::GetCurrent(args); |
||
2983 |
env->StopProfilerIdleNotifier(); |
||
2984 |
} |
||
2985 |
|||
2986 |
|||
2987 |
#define READONLY_PROPERTY(obj, str, var) \ |
||
2988 |
do { \ |
||
2989 |
obj->DefineOwnProperty(env->context(), \ |
||
2990 |
OneByteString(env->isolate(), str), \ |
||
2991 |
var, \ |
||
2992 |
v8::ReadOnly).FromJust(); \ |
||
2993 |
} while (0) |
||
2994 |
|||
2995 |
#define READONLY_DONT_ENUM_PROPERTY(obj, str, var) \ |
||
2996 |
do { \ |
||
2997 |
obj->DefineOwnProperty(env->context(), \ |
||
2998 |
OneByteString(env->isolate(), str), \ |
||
2999 |
var, \ |
||
3000 |
static_cast<v8::PropertyAttribute>(v8::ReadOnly | \ |
||
3001 |
v8::DontEnum)) \ |
||
3002 |
.FromJust(); \ |
||
3003 |
} while (0) |
||
3004 |
|||
3005 |
|||
3006 |
1750 |
void SetupProcessObject(Environment* env, |
|
3007 |
int argc, |
||
3008 |
const char* const* argv, |
||
3009 |
int exec_argc, |
||
3010 |
const char* const* exec_argv) { |
||
3011 |
3500 |
HandleScope scope(env->isolate()); |
|
3012 |
|||
3013 |
1750 |
Local<Object> process = env->process_object(); |
|
3014 |
|||
3015 |
1750 |
auto title_string = FIXED_ONE_BYTE_STRING(env->isolate(), "title"); |
|
3016 |
✗✓ | 8750 |
CHECK(process->SetAccessor(env->context(), |
3017 |
title_string, |
||
3018 |
ProcessTitleGetter, |
||
3019 |
ProcessTitleSetter, |
||
3020 |
env->as_external()).FromJust()); |
||
3021 |
|||
3022 |
// process.version |
||
3023 |
8750 |
READONLY_PROPERTY(process, |
|
3024 |
"version", |
||
3025 |
FIXED_ONE_BYTE_STRING(env->isolate(), NODE_VERSION)); |
||
3026 |
|||
3027 |
// process.moduleLoadList |
||
3028 |
8750 |
READONLY_PROPERTY(process, |
|
3029 |
"moduleLoadList", |
||
3030 |
env->module_load_list_array()); |
||
3031 |
|||
3032 |
// process.versions |
||
3033 |
1750 |
Local<Object> versions = Object::New(env->isolate()); |
|
3034 |
7000 |
READONLY_PROPERTY(process, "versions", versions); |
|
3035 |
|||
3036 |
const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) |
||
3037 |
"." |
||
3038 |
NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) |
||
3039 |
"." |
||
3040 |
1750 |
NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); |
|
3041 |
8750 |
READONLY_PROPERTY(versions, |
|
3042 |
"http_parser", |
||
3043 |
FIXED_ONE_BYTE_STRING(env->isolate(), http_parser_version)); |
||
3044 |
|||
3045 |
// +1 to get rid of the leading 'v' |
||
3046 |
8750 |
READONLY_PROPERTY(versions, |
|
3047 |
"node", |
||
3048 |
OneByteString(env->isolate(), NODE_VERSION + 1)); |
||
3049 |
8750 |
READONLY_PROPERTY(versions, |
|
3050 |
"v8", |
||
3051 |
OneByteString(env->isolate(), V8::GetVersion())); |
||
3052 |
8750 |
READONLY_PROPERTY(versions, |
|
3053 |
"uv", |
||
3054 |
OneByteString(env->isolate(), uv_version_string())); |
||
3055 |
8750 |
READONLY_PROPERTY(versions, |
|
3056 |
"zlib", |
||
3057 |
FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)); |
||
3058 |
8750 |
READONLY_PROPERTY(versions, |
|
3059 |
"ares", |
||
3060 |
FIXED_ONE_BYTE_STRING(env->isolate(), ARES_VERSION_STR)); |
||
3061 |
|||
3062 |
#if defined(NODE_HAVE_I18N_SUPPORT) && defined(U_ICU_VERSION) |
||
3063 |
// ICU-related versions are now handled on the js side, see bootstrap_node.js |
||
3064 |
|||
3065 |
✗✓ | 1750 |
if (icu_data_dir != nullptr) { |
3066 |
// Did the user attempt (via env var or parameter) to set an ICU path? |
||
3067 |
READONLY_PROPERTY(process, |
||
3068 |
"icu_data_dir", |
||
3069 |
OneByteString(env->isolate(), icu_data_dir)); |
||
3070 |
} |
||
3071 |
#endif |
||
3072 |
|||
3073 |
1750 |
const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION); |
|
3074 |
8750 |
READONLY_PROPERTY( |
|
3075 |
versions, |
||
3076 |
"modules", |
||
3077 |
FIXED_ONE_BYTE_STRING(env->isolate(), node_modules_version)); |
||
3078 |
|||
3079 |
// process._promiseRejectEvent |
||
3080 |
1750 |
Local<Object> promiseRejectEvent = Object::New(env->isolate()); |
|
3081 |
7000 |
READONLY_DONT_ENUM_PROPERTY(process, |
|
3082 |
"_promiseRejectEvent", |
||
3083 |
promiseRejectEvent); |
||
3084 |
8750 |
READONLY_PROPERTY(promiseRejectEvent, |
|
3085 |
"unhandled", |
||
3086 |
Integer::New(env->isolate(), |
||
3087 |
v8::kPromiseRejectWithNoHandler)); |
||
3088 |
8750 |
READONLY_PROPERTY(promiseRejectEvent, |
|
3089 |
"handled", |
||
3090 |
Integer::New(env->isolate(), |
||
3091 |
v8::kPromiseHandlerAddedAfterReject)); |
||
3092 |
|||
3093 |
#if HAVE_OPENSSL |
||
3094 |
// Stupid code to slice out the version string. |
||
3095 |
{ // NOLINT(whitespace/braces) |
||
3096 |
size_t i, j, k; |
||
3097 |
int c; |
||
3098 |
✓✗ | 15750 |
for (i = j = 0, k = sizeof(OPENSSL_VERSION_TEXT) - 1; i < k; ++i) { |
3099 |
15750 |
c = OPENSSL_VERSION_TEXT[i]; |
|
3100 |
✓✓ | 15750 |
if ('0' <= c && c <= '9') { |
3101 |
✓✗ | 10500 |
for (j = i + 1; j < k; ++j) { |
3102 |
10500 |
c = OPENSSL_VERSION_TEXT[j]; |
|
3103 |
✓✓ | 10500 |
if (c == ' ') |
3104 |
break; |
||
3105 |
} |
||
3106 |
break; |
||
3107 |
} |
||
3108 |
} |
||
3109 |
8750 |
READONLY_PROPERTY( |
|
3110 |
versions, |
||
3111 |
"openssl", |
||
3112 |
OneByteString(env->isolate(), &OPENSSL_VERSION_TEXT[i], j - i)); |
||
3113 |
} |
||
3114 |
#endif |
||
3115 |
|||
3116 |
// process.arch |
||
3117 |
8750 |
READONLY_PROPERTY(process, "arch", OneByteString(env->isolate(), NODE_ARCH)); |
|
3118 |
|||
3119 |
// process.platform |
||
3120 |
8750 |
READONLY_PROPERTY(process, |
|
3121 |
"platform", |
||
3122 |
OneByteString(env->isolate(), NODE_PLATFORM)); |
||
3123 |
|||
3124 |
// process.release |
||
3125 |
1750 |
Local<Object> release = Object::New(env->isolate()); |
|
3126 |
7000 |
READONLY_PROPERTY(process, "release", release); |
|
3127 |
8750 |
READONLY_PROPERTY(release, "name", OneByteString(env->isolate(), "node")); |
|
3128 |
|||
3129 |
// if this is a release build and no explicit base has been set |
||
3130 |
// substitute the standard release download URL |
||
3131 |
#ifndef NODE_RELEASE_URLBASE |
||
3132 |
# if NODE_VERSION_IS_RELEASE |
||
3133 |
# define NODE_RELEASE_URLBASE "https://nodejs.org/download/release/" |
||
3134 |
# endif |
||
3135 |
#endif |
||
3136 |
|||
3137 |
#if defined(NODE_RELEASE_URLBASE) |
||
3138 |
# define NODE_RELEASE_URLPFX NODE_RELEASE_URLBASE "v" NODE_VERSION_STRING "/" |
||
3139 |
# define NODE_RELEASE_URLFPFX NODE_RELEASE_URLPFX "node-v" NODE_VERSION_STRING |
||
3140 |
|||
3141 |
READONLY_PROPERTY(release, |
||
3142 |
"sourceUrl", |
||
3143 |
OneByteString(env->isolate(), |
||
3144 |
NODE_RELEASE_URLFPFX ".tar.gz")); |
||
3145 |
READONLY_PROPERTY(release, |
||
3146 |
"headersUrl", |
||
3147 |
OneByteString(env->isolate(), |
||
3148 |
NODE_RELEASE_URLFPFX "-headers.tar.gz")); |
||
3149 |
# ifdef _WIN32 |
||
3150 |
READONLY_PROPERTY(release, |
||
3151 |
"libUrl", |
||
3152 |
OneByteString(env->isolate(), |
||
3153 |
strcmp(NODE_ARCH, "ia32") ? NODE_RELEASE_URLPFX "win-" |
||
3154 |
NODE_ARCH "/node.lib" |
||
3155 |
: NODE_RELEASE_URLPFX |
||
3156 |
"win-x86/node.lib")); |
||
3157 |
# endif |
||
3158 |
#endif |
||
3159 |
|||
3160 |
// process.argv |
||
3161 |
1750 |
Local<Array> arguments = Array::New(env->isolate(), argc); |
|
3162 |
✓✓ | 5499 |
for (int i = 0; i < argc; ++i) { |
3163 |
11247 |
arguments->Set(i, String::NewFromUtf8(env->isolate(), argv[i])); |
|
3164 |
} |
||
3165 |
3500 |
process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "argv"), arguments); |
|
3166 |
|||
3167 |
// process.execArgv |
||
3168 |
1750 |
Local<Array> exec_arguments = Array::New(env->isolate(), exec_argc); |
|
3169 |
✓✓ | 2072 |
for (int i = 0; i < exec_argc; ++i) { |
3170 |
966 |
exec_arguments->Set(i, String::NewFromUtf8(env->isolate(), exec_argv[i])); |
|
3171 |
} |
||
3172 |
5250 |
process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"), |
|
3173 |
1750 |
exec_arguments); |
|
3174 |
|||
3175 |
// create process.env |
||
3176 |
Local<ObjectTemplate> process_env_template = |
||
3177 |
1750 |
ObjectTemplate::New(env->isolate()); |
|
3178 |
7000 |
process_env_template->SetHandler(NamedPropertyHandlerConfiguration( |
|
3179 |
EnvGetter, |
||
3180 |
EnvSetter, |
||
3181 |
EnvQuery, |
||
3182 |
EnvDeleter, |
||
3183 |
EnvEnumerator, |
||
3184 |
1750 |
env->as_external())); |
|
3185 |
|||
3186 |
Local<Object> process_env = |
||
3187 |
3500 |
process_env_template->NewInstance(env->context()).ToLocalChecked(); |
|
3188 |
3500 |
process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "env"), process_env); |
|
3189 |
|||
3190 |
8750 |
READONLY_PROPERTY(process, "pid", Integer::New(env->isolate(), getpid())); |
|
3191 |
8750 |
READONLY_PROPERTY(process, "features", GetFeatures(env)); |
|
3192 |
|||
3193 |
auto need_immediate_callback_string = |
||
3194 |
1750 |
FIXED_ONE_BYTE_STRING(env->isolate(), "_needImmediateCallback"); |
|
3195 |
✗✓ | 8750 |
CHECK(process->SetAccessor(env->context(), need_immediate_callback_string, |
3196 |
NeedImmediateCallbackGetter, |
||
3197 |
NeedImmediateCallbackSetter, |
||
3198 |
env->as_external()).FromJust()); |
||
3199 |
|||
3200 |
// -e, --eval |
||
3201 |
✓✓ | 1750 |
if (eval_string) { |
3202 |
335 |
READONLY_PROPERTY(process, |
|
3203 |
"_eval", |
||
3204 |
String::NewFromUtf8(env->isolate(), eval_string)); |
||
3205 |
} |
||
3206 |
|||
3207 |
// -p, --print |
||
3208 |
✓✓ | 1750 |
if (print_eval) { |
3209 |
132 |
READONLY_PROPERTY(process, "_print_eval", True(env->isolate())); |
|
3210 |
} |
||
3211 |
|||
3212 |
// -c, --check |
||
3213 |
✓✓ | 1750 |
if (syntax_check_only) { |
3214 |
132 |
READONLY_PROPERTY(process, "_syntax_check_only", True(env->isolate())); |
|
3215 |
} |
||
3216 |
|||
3217 |
// -i, --interactive |
||
3218 |
✓✓ | 1750 |
if (force_repl) { |
3219 |
102 |
READONLY_PROPERTY(process, "_forceRepl", True(env->isolate())); |
|
3220 |
} |
||
3221 |
|||
3222 |
✓✓ | 1750 |
if (preload_module_count) { |
3223 |
✗✓ | 13 |
CHECK(preload_modules); |
3224 |
13 |
Local<Array> array = Array::New(env->isolate()); |
|
3225 |
✓✓ | 30 |
for (unsigned int i = 0; i < preload_module_count; ++i) { |
3226 |
Local<String> module = String::NewFromUtf8(env->isolate(), |
||
3227 |
17 |
preload_modules[i]); |
|
3228 |
34 |
array->Set(i, module); |
|
3229 |
} |
||
3230 |
52 |
READONLY_PROPERTY(process, |
|
3231 |
"_preload_modules", |
||
3232 |
array); |
||
3233 |
|||
3234 |
✓✗ | 13 |
delete[] preload_modules; |
3235 |
13 |
preload_modules = nullptr; |
|
3236 |
13 |
preload_module_count = 0; |
|
3237 |
} |
||
3238 |
|||
3239 |
// --no-deprecation |
||
3240 |
✓✓ | 1750 |
if (no_deprecation) { |
3241 |
6 |
READONLY_PROPERTY(process, "noDeprecation", True(env->isolate())); |
|
3242 |
} |
||
3243 |
|||
3244 |
✓✓ | 1750 |
if (no_process_warnings) { |
3245 |
42 |
READONLY_PROPERTY(process, "noProcessWarnings", True(env->isolate())); |
|
3246 |
} |
||
3247 |
|||
3248 |
✓✓ | 1750 |
if (trace_warnings) { |
3249 |
6 |
READONLY_PROPERTY(process, "traceProcessWarnings", True(env->isolate())); |
|
3250 |
} |
||
3251 |
|||
3252 |
// --throw-deprecation |
||
3253 |
✗✓ | 1750 |
if (throw_deprecation) { |
3254 |
READONLY_PROPERTY(process, "throwDeprecation", True(env->isolate())); |
||
3255 |
} |
||
3256 |
|||
3257 |
#ifdef NODE_NO_BROWSER_GLOBALS |
||
3258 |
// configure --no-browser-globals |
||
3259 |
READONLY_PROPERTY(process, "_noBrowserGlobals", True(env->isolate())); |
||
3260 |
#endif // NODE_NO_BROWSER_GLOBALS |
||
3261 |
|||
3262 |
// --prof-process |
||
3263 |
✗✓ | 1750 |
if (prof_process) { |
3264 |
READONLY_PROPERTY(process, "profProcess", True(env->isolate())); |
||
3265 |
} |
||
3266 |
|||
3267 |
// --trace-deprecation |
||
3268 |
✓✓ | 1750 |
if (trace_deprecation) { |
3269 |
6 |
READONLY_PROPERTY(process, "traceDeprecation", True(env->isolate())); |
|
3270 |
} |
||
3271 |
|||
3272 |
// --debug-brk |
||
3273 |
✓✓ | 1750 |
if (debug_options.wait_for_connect()) { |
3274 |
12 |
READONLY_PROPERTY(process, "_debugWaitConnect", True(env->isolate())); |
|
3275 |
} |
||
3276 |
|||
3277 |
// --security-revert flags |
||
3278 |
#define V(code, _, __) \ |
||
3279 |
do { \ |
||
3280 |
if (IsReverted(REVERT_ ## code)) { \ |
||
3281 |
READONLY_PROPERTY(process, "REVERT_" #code, True(env->isolate())); \ |
||
3282 |
} \ |
||
3283 |
} while (0); |
||
3284 |
REVERSIONS(V) |
||
3285 |
#undef V |
||
3286 |
|||
3287 |
1750 |
size_t exec_path_len = 2 * PATH_MAX; |
|
3288 |
1750 |
char* exec_path = new char[exec_path_len]; |
|
3289 |
1750 |
Local<String> exec_path_value; |
|
3290 |
✓✗ | 1750 |
if (uv_exepath(exec_path, &exec_path_len) == 0) { |
3291 |
exec_path_value = String::NewFromUtf8(env->isolate(), |
||
3292 |
exec_path, |
||
3293 |
String::kNormalString, |
||
3294 |
1750 |
exec_path_len); |
|
3295 |
} else { |
||
3296 |
exec_path_value = String::NewFromUtf8(env->isolate(), argv[0]); |
||
3297 |
} |
||
3298 |
5250 |
process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"), |
|
3299 |
1750 |
exec_path_value); |
|
3300 |
✓✗ | 1750 |
delete[] exec_path; |
3301 |
|||
3302 |
1750 |
auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort"); |
|
3303 |
✗✓ | 8750 |
CHECK(process->SetAccessor(env->context(), |
3304 |
debug_port_string, |
||
3305 |
DebugPortGetter, |
||
3306 |
DebugPortSetter, |
||
3307 |
env->as_external()).FromJust()); |
||
3308 |
|||
3309 |
// define various internal methods |
||
3310 |
env->SetMethod(process, |
||
3311 |
"_startProfilerIdleNotifier", |
||
3312 |
1750 |
StartProfilerIdleNotifier); |
|
3313 |
env->SetMethod(process, |
||
3314 |
"_stopProfilerIdleNotifier", |
||
3315 |
1750 |
StopProfilerIdleNotifier); |
|
3316 |
1750 |
env->SetMethod(process, "_getActiveRequests", GetActiveRequests); |
|
3317 |
1750 |
env->SetMethod(process, "_getActiveHandles", GetActiveHandles); |
|
3318 |
1750 |
env->SetMethod(process, "reallyExit", Exit); |
|
3319 |
1750 |
env->SetMethod(process, "abort", Abort); |
|
3320 |
1750 |
env->SetMethod(process, "chdir", Chdir); |
|
3321 |
1750 |
env->SetMethod(process, "cwd", Cwd); |
|
3322 |
|||
3323 |
1750 |
env->SetMethod(process, "umask", Umask); |
|
3324 |
|||
3325 |
#if defined(__POSIX__) && !defined(__ANDROID__) |
||
3326 |
1750 |
env->SetMethod(process, "getuid", GetUid); |
|
3327 |
1750 |
env->SetMethod(process, "geteuid", GetEUid); |
|
3328 |
1750 |
env->SetMethod(process, "setuid", SetUid); |
|
3329 |
1750 |
env->SetMethod(process, "seteuid", SetEUid); |
|
3330 |
|||
3331 |
1750 |
env->SetMethod(process, "setgid", SetGid); |
|
3332 |
1750 |
env->SetMethod(process, "setegid", SetEGid); |
|
3333 |
1750 |
env->SetMethod(process, "getgid", GetGid); |
|
3334 |
1750 |
env->SetMethod(process, "getegid", GetEGid); |
|
3335 |
|||
3336 |
1750 |
env->SetMethod(process, "getgroups", GetGroups); |
|
3337 |
1750 |
env->SetMethod(process, "setgroups", SetGroups); |
|
3338 |
1750 |
env->SetMethod(process, "initgroups", InitGroups); |
|
3339 |
#endif // __POSIX__ && !defined(__ANDROID__) |
||
3340 |
|||
3341 |
1750 |
env->SetMethod(process, "_kill", Kill); |
|
3342 |
|||
3343 |
1750 |
env->SetMethod(process, "_debugProcess", DebugProcess); |
|
3344 |
1750 |
env->SetMethod(process, "_debugPause", DebugPause); |
|
3345 |
1750 |
env->SetMethod(process, "_debugEnd", DebugEnd); |
|
3346 |
|||
3347 |
1750 |
env->SetMethod(process, "hrtime", Hrtime); |
|
3348 |
|||
3349 |
1750 |
env->SetMethod(process, "cpuUsage", CPUUsage); |
|
3350 |
|||
3351 |
1750 |
env->SetMethod(process, "dlopen", DLOpen); |
|
3352 |
|||
3353 |
1750 |
env->SetMethod(process, "uptime", Uptime); |
|
3354 |
1750 |
env->SetMethod(process, "memoryUsage", MemoryUsage); |
|
3355 |
|||
3356 |
1750 |
env->SetMethod(process, "binding", Binding); |
|
3357 |
1750 |
env->SetMethod(process, "_linkedBinding", LinkedBinding); |
|
3358 |
|||
3359 |
1750 |
env->SetMethod(process, "_setupProcessObject", SetupProcessObject); |
|
3360 |
1750 |
env->SetMethod(process, "_setupNextTick", SetupNextTick); |
|
3361 |
1750 |
env->SetMethod(process, "_setupPromises", SetupPromises); |
|
3362 |
1750 |
env->SetMethod(process, "_setupDomainUse", SetupDomainUse); |
|
3363 |
|||
3364 |
// pre-set _events object for faster emit checks |
||
3365 |
1750 |
Local<Object> events_obj = Object::New(env->isolate()); |
|
3366 |
✗✓ | 10500 |
CHECK(events_obj->SetPrototype(env->context(), |
3367 |
Null(env->isolate())).FromJust()); |
||
3368 |
5250 |
process->Set(env->events_string(), events_obj); |
|
3369 |
1750 |
} |
|
3370 |
|||
3371 |
|||
3372 |
#undef READONLY_PROPERTY |
||
3373 |
|||
3374 |
|||
3375 |
void SignalExit(int signo) { |
||
3376 |
uv_tty_reset_mode(); |
||
3377 |
if (trace_enabled) { |
||
3378 |
tracing_agent->Stop(); |
||
3379 |
} |
||
3380 |
#ifdef __FreeBSD__ |
||
3381 |
// FreeBSD has a nasty bug, see RegisterSignalHandler for details |
||
3382 |
struct sigaction sa; |
||
3383 |
memset(&sa, 0, sizeof(sa)); |
||
3384 |
sa.sa_handler = SIG_DFL; |
||
3385 |
CHECK_EQ(sigaction(signo, &sa, nullptr), 0); |
||
3386 |
#endif |
||
3387 |
raise(signo); |
||
3388 |
} |
||
3389 |
|||
3390 |
|||
3391 |
// Most of the time, it's best to use `console.error` to write |
||
3392 |
// to the process.stderr stream. However, in some cases, such as |
||
3393 |
// when debugging the stream.Writable class or the process.nextTick |
||
3394 |
// function, it is useful to bypass JavaScript entirely. |
||
3395 |
7 |
static void RawDebug(const FunctionCallbackInfo<Value>& args) { |
|
3396 |
✓✗✗✓ ✓✗✗✓ |
28 |
CHECK(args.Length() == 1 && args[0]->IsString() && |
3397 |
"must be called with a single string"); |
||
3398 |
21 |
node::Utf8Value message(args.GetIsolate(), args[0]); |
|
3399 |
7 |
PrintErrorString("%s\n", *message); |
|
3400 |
7 |
fflush(stderr); |
|
3401 |
7 |
} |
|
3402 |
|||
3403 |
|||
3404 |
1750 |
void LoadEnvironment(Environment* env) { |
|
3405 |
3412 |
HandleScope handle_scope(env->isolate()); |
|
3406 |
|||
3407 |
3412 |
TryCatch try_catch(env->isolate()); |
|
3408 |
|||
3409 |
// Disable verbose mode to stop FatalException() handler from trying |
||
3410 |
// to handle the exception. Errors this early in the start-up phase |
||
3411 |
// are not safe to ignore. |
||
3412 |
1750 |
try_catch.SetVerbose(false); |
|
3413 |
|||
3414 |
// Execute the lib/internal/bootstrap_node.js file which was included as a |
||
3415 |
// static C string in node_natives.h by node_js2c. |
||
3416 |
// 'internal_bootstrap_node_native' is the string containing that source code. |
||
3417 |
1750 |
Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(), |
|
3418 |
"bootstrap_node.js"); |
||
3419 |
1750 |
Local<Value> f_value = ExecuteString(env, MainSource(env), script_name); |
|
3420 |
✗✓ | 1750 |
if (try_catch.HasCaught()) { |
3421 |
ReportException(env, try_catch); |
||
3422 |
exit(10); |
||
3423 |
} |
||
3424 |
// The bootstrap_node.js file returns a function 'f' |
||
3425 |
✗✓ | 1750 |
CHECK(f_value->IsFunction()); |
3426 |
1750 |
Local<Function> f = Local<Function>::Cast(f_value); |
|
3427 |
|||
3428 |
// Add a reference to the global object |
||
3429 |
1750 |
Local<Object> global = env->context()->Global(); |
|
3430 |
|||
3431 |
#if defined HAVE_DTRACE || defined HAVE_ETW |
||
3432 |
InitDTrace(env, global); |
||
3433 |
#endif |
||
3434 |
|||
3435 |
#if defined HAVE_LTTNG |
||
3436 |
InitLTTNG(env, global); |
||
3437 |
#endif |
||
3438 |
|||
3439 |
#if defined HAVE_PERFCTR |
||
3440 |
InitPerfCounters(env, global); |
||
3441 |
#endif |
||
3442 |
|||
3443 |
// Enable handling of uncaught exceptions |
||
3444 |
// (FatalException(), break on uncaught exception in debugger) |
||
3445 |
// |
||
3446 |
// This is not strictly necessary since it's almost impossible |
||
3447 |
// to attach the debugger fast enought to break on exception |
||
3448 |
// thrown during process startup. |
||
3449 |
1750 |
try_catch.SetVerbose(true); |
|
3450 |
|||
3451 |
1750 |
env->SetMethod(env->process_object(), "_rawDebug", RawDebug); |
|
3452 |
|||
3453 |
// Expose the global object as a property on itself |
||
3454 |
// (Allows you to set stuff on `global` from anywhere in JavaScript.) |
||
3455 |
3500 |
global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global); |
|
3456 |
|||
3457 |
// Now we call 'f' with the 'process' variable that we've built up with |
||
3458 |
// all our bindings. Inside bootstrap_node.js and internal/process we'll |
||
3459 |
// take care of assigning things to their places. |
||
3460 |
|||
3461 |
// We start the process this way in order to be more modular. Developers |
||
3462 |
// who do not like how bootstrap_node.js sets up the module system but do |
||
3463 |
// like Node's I/O bindings may want to replace 'f' with their own function. |
||
3464 |
3500 |
Local<Value> arg = env->process_object(); |
|
3465 |
5250 |
f->Call(Null(env->isolate()), 1, &arg); |
|
3466 |
1662 |
} |
|
3467 |
|||
3468 |
static void PrintHelp() { |
||
3469 |
// XXX: If you add an option here, please also add it to doc/node.1 and |
||
3470 |
// doc/api/cli.md |
||
3471 |
printf("Usage: node [options] [ -e script | script.js ] [arguments] \n" |
||
3472 |
" node debug script.js [arguments] \n" |
||
3473 |
"\n" |
||
3474 |
"Options:\n" |
||
3475 |
" -v, --version print Node.js version\n" |
||
3476 |
" -e, --eval script evaluate script\n" |
||
3477 |
" -p, --print evaluate script and print result\n" |
||
3478 |
" -c, --check syntax check script without executing\n" |
||
3479 |
" -i, --interactive always enter the REPL even if stdin\n" |
||
3480 |
" does not appear to be a terminal\n" |
||
3481 |
" -r, --require module to preload (option can be " |
||
3482 |
"repeated)\n" |
||
3483 |
" --no-deprecation silence deprecation warnings\n" |
||
3484 |
" --trace-deprecation show stack traces on deprecations\n" |
||
3485 |
" --throw-deprecation throw an exception on deprecations\n" |
||
3486 |
" --no-warnings silence all process warnings\n" |
||
3487 |
" --trace-warnings show stack traces on process warnings\n" |
||
3488 |
" --trace-sync-io show stack trace when use of sync IO\n" |
||
3489 |
" is detected after the first tick\n" |
||
3490 |
" --trace-events-enabled track trace events\n" |
||
3491 |
" --trace-event-categories comma separated list of trace event\n" |
||
3492 |
" categories to record\n" |
||
3493 |
" --track-heap-objects track heap object allocations for heap " |
||
3494 |
"snapshots\n" |
||
3495 |
" --prof-process process v8 profiler output generated\n" |
||
3496 |
" using --prof\n" |
||
3497 |
" --zero-fill-buffers automatically zero-fill all newly " |
||
3498 |
"allocated\n" |
||
3499 |
" Buffer and SlowBuffer instances\n" |
||
3500 |
" --v8-options print v8 command line options\n" |
||
3501 |
" --v8-pool-size=num set v8's thread pool size\n" |
||
3502 |
#if HAVE_OPENSSL |
||
3503 |
" --tls-cipher-list=val use an alternative default TLS cipher " |
||
3504 |
"list\n" |
||
3505 |
#if NODE_FIPS_MODE |
||
3506 |
" --enable-fips enable FIPS crypto at startup\n" |
||
3507 |
" --force-fips force FIPS crypto (cannot be disabled)\n" |
||
3508 |
#endif /* NODE_FIPS_MODE */ |
||
3509 |
" --openssl-config=path load OpenSSL configuration file from the\n" |
||
3510 |
" specified path\n" |
||
3511 |
#endif /* HAVE_OPENSSL */ |
||
3512 |
#if defined(NODE_HAVE_I18N_SUPPORT) |
||
3513 |
" --icu-data-dir=dir set ICU data load path to dir\n" |
||
3514 |
" (overrides NODE_ICU_DATA)\n" |
||
3515 |
#if !defined(NODE_HAVE_SMALL_ICU) |
||
3516 |
" note: linked-in ICU data is present\n" |
||
3517 |
#endif |
||
3518 |
" --preserve-symlinks preserve symbolic links when resolving\n" |
||
3519 |
" and caching modules\n" |
||
3520 |
#endif |
||
3521 |
"\n" |
||
3522 |
"Environment variables:\n" |
||
3523 |
"NODE_DEBUG ','-separated list of core modules that\n" |
||
3524 |
" should print debug information\n" |
||
3525 |
"NODE_DISABLE_COLORS set to 1 to disable colors in the REPL\n" |
||
3526 |
"NODE_EXTRA_CA_CERTS path to additional CA certificates file\n" |
||
3527 |
#if defined(NODE_HAVE_I18N_SUPPORT) |
||
3528 |
"NODE_ICU_DATA data path for ICU (Intl object) data\n" |
||
3529 |
#if !defined(NODE_HAVE_SMALL_ICU) |
||
3530 |
" (will extend linked-in data)\n" |
||
3531 |
#endif |
||
3532 |
#endif |
||
3533 |
#ifdef _WIN32 |
||
3534 |
"NODE_PATH ';'-separated list of directories\n" |
||
3535 |
#else |
||
3536 |
"NODE_PATH ':'-separated list of directories\n" |
||
3537 |
#endif |
||
3538 |
" prefixed to the module search path\n" |
||
3539 |
"NODE_REPL_HISTORY path to the persistent REPL history file\n" |
||
3540 |
"\n" |
||
3541 |
"Documentation can be found at https://nodejs.org/\n"); |
||
3542 |
} |
||
3543 |
|||
3544 |
|||
3545 |
// Parse command line arguments. |
||
3546 |
// |
||
3547 |
// argv is modified in place. exec_argv and v8_argv are out arguments that |
||
3548 |
// ParseArgs() allocates memory for and stores a pointer to the output |
||
3549 |
// vector in. The caller should free them with delete[]. |
||
3550 |
// |
||
3551 |
// On exit: |
||
3552 |
// |
||
3553 |
// * argv contains the arguments with node and V8 options filtered out. |
||
3554 |
// * exec_argv contains both node and V8 options and nothing else. |
||
3555 |
// * v8_argv contains argv[0] plus any V8 options |
||
3556 |
1757 |
static void ParseArgs(int* argc, |
|
3557 |
const char** argv, |
||
3558 |
int* exec_argc, |
||
3559 |
const char*** exec_argv, |
||
3560 |
int* v8_argc, |
||
3561 |
const char*** v8_argv) { |
||
3562 |
1757 |
const unsigned int nargs = static_cast<unsigned int>(*argc); |
|
3563 |
✓✗ | 1757 |
const char** new_exec_argv = new const char*[nargs]; |
3564 |
✓✗ | 1757 |
const char** new_v8_argv = new const char*[nargs]; |
3565 |
✓✗ | 1757 |
const char** new_argv = new const char*[nargs]; |
3566 |
✓✗ | 1757 |
const char** local_preload_modules = new const char*[nargs]; |
3567 |
|||
3568 |
✓✓ | 5854 |
for (unsigned int i = 0; i < nargs; ++i) { |
3569 |
4097 |
new_exec_argv[i] = nullptr; |
|
3570 |
4097 |
new_v8_argv[i] = nullptr; |
|
3571 |
4097 |
new_argv[i] = nullptr; |
|
3572 |
4097 |
local_preload_modules[i] = nullptr; |
|
3573 |
} |
||
3574 |
|||
3575 |
// exec_argv starts with the first option, the other two start with argv[0]. |
||
3576 |
1757 |
unsigned int new_exec_argc = 0; |
|
3577 |
1757 |
unsigned int new_v8_argc = 1; |
|
3578 |
1757 |
unsigned int new_argc = 1; |
|
3579 |
1757 |
new_v8_argv[0] = argv[0]; |
|
3580 |
1757 |
new_argv[0] = argv[0]; |
|
3581 |
|||
3582 |
1757 |
unsigned int index = 1; |
|
3583 |
1757 |
bool short_circuit = false; |
|
3584 |
✓✓✓✓ ✓✗ |
2255 |
while (index < nargs && argv[index][0] == '-' && !short_circuit) { |
3585 |
252 |
const char* const arg = argv[index]; |
|
3586 |
252 |
unsigned int args_consumed = 1; |
|
3587 |
|||
3588 |
✓✓ | 1008 |
if (debug_options.ParseOption(arg)) { |
3589 |
// Done, consumed by DebugOptions::ParseOption(). |
||
3590 |
✓✗✓✓ |
229 |
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) { |
3591 |
2 |
printf("%s\n", NODE_VERSION); |
|
3592 |
2 |
exit(0); |
|
3593 |
✓✗✗✓ |
227 |
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) { |
3594 |
PrintHelp(); |
||
3595 |
exit(0); |
||
3596 |
✓✓✓✓ |
450 |
} else if (strcmp(arg, "--eval") == 0 || |
3597 |
✓✓ | 392 |
strcmp(arg, "-e") == 0 || |
3598 |
✓✓ | 335 |
strcmp(arg, "--print") == 0 || |
3599 |
✓✓ | 325 |
strcmp(arg, "-pe") == 0 || |
3600 |
159 |
strcmp(arg, "-p") == 0) { |
|
3601 |
80 |
bool is_eval = strchr(arg, 'e') != nullptr; |
|
3602 |
80 |
bool is_print = strchr(arg, 'p') != nullptr; |
|
3603 |
✓✓✓✓ |
80 |
print_eval = print_eval || is_print; |
3604 |
// --eval, -e and -pe always require an argument. |
||
3605 |
✓✓ | 80 |
if (is_eval == true) { |
3606 |
65 |
args_consumed += 1; |
|
3607 |
65 |
eval_string = argv[index + 1]; |
|
3608 |
✓✓ | 65 |
if (eval_string == nullptr) { |
3609 |
2 |
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg); |
|
3610 |
1 |
exit(9); |
|
3611 |
} |
||
3612 |
✓✗✓✗ |
30 |
} else if ((index + 1 < nargs) && |
3613 |
✓✓ | 30 |
argv[index + 1] != nullptr && |
3614 |
15 |
argv[index + 1][0] != '-') { |
|
3615 |
13 |
args_consumed += 1; |
|
3616 |
13 |
eval_string = argv[index + 1]; |
|
3617 |
✓✓ | 13 |
if (strncmp(eval_string, "\\-", 2) == 0) { |
3618 |
// Starts with "\\-": escaped expression, drop the backslash. |
||
3619 |
1 |
eval_string += 1; |
|
3620 |
} |
||
3621 |
} |
||
3622 |
✓✓✓✓ |
288 |
} else if (strcmp(arg, "--require") == 0 || |
3623 |
141 |
strcmp(arg, "-r") == 0) { |
|
3624 |
17 |
const char* module = argv[index + 1]; |
|
3625 |
✗✓ | 17 |
if (module == nullptr) { |
3626 |
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg); |
||
3627 |
exit(9); |
||
3628 |
} |
||
3629 |
17 |
args_consumed += 1; |
|
3630 |
17 |
local_preload_modules[preload_module_count++] = module; |
|
3631 |
✓✓✓✓ |
130 |
} else if (strcmp(arg, "--check") == 0 || strcmp(arg, "-c") == 0) { |
3632 |
22 |
syntax_check_only = true; |
|
3633 |
✓✓✓✓ |
108 |
} else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) { |
3634 |
15 |
force_repl = true; |
|
3635 |
✓✓ | 93 |
} else if (strcmp(arg, "--no-deprecation") == 0) { |
3636 |
1 |
no_deprecation = true; |
|
3637 |
✓✓ | 92 |
} else if (strcmp(arg, "--no-warnings") == 0) { |
3638 |
7 |
no_process_warnings = true; |
|
3639 |
✓✓ | 85 |
} else if (strcmp(arg, "--trace-warnings") == 0) { |
3640 |
1 |
trace_warnings = true; |
|
3641 |
✓✓ | 84 |
} else if (strcmp(arg, "--trace-deprecation") == 0) { |
3642 |
1 |
trace_deprecation = true; |
|
3643 |
✓✓ | 83 |
} else if (strcmp(arg, "--trace-sync-io") == 0) { |
3644 |
1 |
trace_sync_io = true; |
|
3645 |
✓✓ | 82 |
} else if (strcmp(arg, "--trace-events-enabled") == 0) { |
3646 |
2 |
trace_enabled = true; |
|
3647 |
✓✓ | 80 |
} else if (strcmp(arg, "--trace-event-categories") == 0) { |
3648 |
1 |
const char* categories = argv[index + 1]; |
|
3649 |
✗✓ | 1 |
if (categories == nullptr) { |
3650 |
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg); |
||
3651 |
exit(9); |
||
3652 |
} |
||
3653 |
1 |
args_consumed += 1; |
|
3654 |
1 |
trace_enabled_categories = categories; |
|
3655 |
✗✓ | 79 |
} else if (strcmp(arg, "--track-heap-objects") == 0) { |
3656 |
track_heap_objects = true; |
||
3657 |
✗✓ | 79 |
} else if (strcmp(arg, "--throw-deprecation") == 0) { |
3658 |
throw_deprecation = true; |
||
3659 |
✗✓ | 79 |
} else if (strncmp(arg, "--security-revert=", 18) == 0) { |
3660 |
const char* cve = arg + 18; |
||
3661 |
Revert(cve); |
||
3662 |
✓✓ | 79 |
} else if (strcmp(arg, "--preserve-symlinks") == 0) { |
3663 |
3 |
config_preserve_symlinks = true; |
|
3664 |
✗✓ | 76 |
} else if (strcmp(arg, "--prof-process") == 0) { |
3665 |
prof_process = true; |
||
3666 |
short_circuit = true; |
||
3667 |
✓✓ | 76 |
} else if (strcmp(arg, "--zero-fill-buffers") == 0) { |
3668 |
1 |
zero_fill_all_buffers = true; |
|
3669 |
✗✓ | 75 |