• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <cerrno>
2 #include <cstdarg>
3 
4 #include "debug_utils-inl.h"
5 #include "node_errors.h"
6 #include "node_internals.h"
7 #include "node_report.h"
8 #include "node_process-inl.h"
9 #include "node_v8_platform-inl.h"
10 #include "util-inl.h"
11 
12 namespace node {
13 
14 using errors::TryCatchScope;
15 using v8::Boolean;
16 using v8::Context;
17 using v8::Exception;
18 using v8::Function;
19 using v8::FunctionCallbackInfo;
20 using v8::HandleScope;
21 using v8::Int32;
22 using v8::Isolate;
23 using v8::Just;
24 using v8::Local;
25 using v8::Maybe;
26 using v8::MaybeLocal;
27 using v8::Message;
28 using v8::Object;
29 using v8::ScriptOrigin;
30 using v8::StackFrame;
31 using v8::StackTrace;
32 using v8::String;
33 using v8::Undefined;
34 using v8::Value;
35 
IsExceptionDecorated(Environment * env,Local<Value> er)36 bool IsExceptionDecorated(Environment* env, Local<Value> er) {
37   if (!er.IsEmpty() && er->IsObject()) {
38     Local<Object> err_obj = er.As<Object>();
39     auto maybe_value =
40         err_obj->GetPrivate(env->context(), env->decorated_private_symbol());
41     Local<Value> decorated;
42     return maybe_value.ToLocal(&decorated) && decorated->IsTrue();
43   }
44   return false;
45 }
46 
47 namespace per_process {
48 static Mutex tty_mutex;
49 }  // namespace per_process
50 
GetErrorSource(Isolate * isolate,Local<Context> context,Local<Message> message,bool * added_exception_line)51 static std::string GetErrorSource(Isolate* isolate,
52                                   Local<Context> context,
53                                   Local<Message> message,
54                                   bool* added_exception_line) {
55   MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
56   node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
57   std::string sourceline(*encoded_source, encoded_source.length());
58   *added_exception_line = false;
59 
60   // If source maps have been enabled, the exception line will instead be
61   // added in the JavaScript context:
62   Environment* env = Environment::GetCurrent(isolate);
63   const bool has_source_map_url =
64       !message->GetScriptOrigin().SourceMapUrl().IsEmpty();
65   if (has_source_map_url && env != nullptr && env->source_maps_enabled()) {
66     return sourceline;
67   }
68 
69   if (sourceline.find("node-do-not-add-exception-line") != std::string::npos) {
70     return sourceline;
71   }
72 
73   // Because of how node modules work, all scripts are wrapped with a
74   // "function (module, exports, __filename, ...) {"
75   // to provide script local variables.
76   //
77   // When reporting errors on the first line of a script, this wrapper
78   // function is leaked to the user. There used to be a hack here to
79   // truncate off the first 62 characters, but it caused numerous other
80   // problems when vm.runIn*Context() methods were used for non-module
81   // code.
82   //
83   // If we ever decide to re-instate such a hack, the following steps
84   // must be taken:
85   //
86   // 1. Pass a flag around to say "this code was wrapped"
87   // 2. Update the stack frame output so that it is also correct.
88   //
89   // It would probably be simpler to add a line rather than add some
90   // number of characters to the first line, since V8 truncates the
91   // sourceline to 78 characters, and we end up not providing very much
92   // useful debugging info to the user if we remove 62 characters.
93 
94   // Print (filename):(line number): (message).
95   ScriptOrigin origin = message->GetScriptOrigin();
96   node::Utf8Value filename(isolate, message->GetScriptResourceName());
97   const char* filename_string = *filename;
98   int linenum = message->GetLineNumber(context).FromJust();
99 
100   int script_start = (linenum - origin.ResourceLineOffset()->Value()) == 1
101                          ? origin.ResourceColumnOffset()->Value()
102                          : 0;
103   int start = message->GetStartColumn(context).FromMaybe(0);
104   int end = message->GetEndColumn(context).FromMaybe(0);
105   if (start >= script_start) {
106     CHECK_GE(end, start);
107     start -= script_start;
108     end -= script_start;
109   }
110 
111   std::string buf = SPrintF("%s:%i\n%s\n",
112                             filename_string,
113                             linenum,
114                             sourceline.c_str());
115   CHECK_GT(buf.size(), 0);
116   *added_exception_line = true;
117 
118   if (start > end ||
119       start < 0 ||
120       static_cast<size_t>(end) > sourceline.size()) {
121     return buf;
122   }
123 
124   constexpr int kUnderlineBufsize = 1020;
125   char underline_buf[kUnderlineBufsize + 4];
126   int off = 0;
127   // Print wavy underline (GetUnderline is deprecated).
128   for (int i = 0; i < start; i++) {
129     if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
130       break;
131     }
132     CHECK_LT(off, kUnderlineBufsize);
133     underline_buf[off++] = (sourceline[i] == '\t') ? '\t' : ' ';
134   }
135   for (int i = start; i < end; i++) {
136     if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
137       break;
138     }
139     CHECK_LT(off, kUnderlineBufsize);
140     underline_buf[off++] = '^';
141   }
142   CHECK_LE(off, kUnderlineBufsize);
143   underline_buf[off++] = '\n';
144 
145   return buf + std::string(underline_buf, off);
146 }
147 
PrintStackTrace(Isolate * isolate,Local<StackTrace> stack)148 void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) {
149   for (int i = 0; i < stack->GetFrameCount(); i++) {
150     Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
151     node::Utf8Value fn_name_s(isolate, stack_frame->GetFunctionName());
152     node::Utf8Value script_name(isolate, stack_frame->GetScriptName());
153     const int line_number = stack_frame->GetLineNumber();
154     const int column = stack_frame->GetColumn();
155 
156     if (stack_frame->IsEval()) {
157       if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
158         FPrintF(stderr, "    at [eval]:%i:%i\n", line_number, column);
159       } else {
160         FPrintF(stderr,
161                 "    at [eval] (%s:%i:%i)\n",
162                 *script_name,
163                 line_number,
164                 column);
165       }
166       break;
167     }
168 
169     if (fn_name_s.length() == 0) {
170       FPrintF(stderr, "    at %s:%i:%i\n", script_name, line_number, column);
171     } else {
172       FPrintF(stderr,
173               "    at %s (%s:%i:%i)\n",
174               fn_name_s,
175               script_name,
176               line_number,
177               column);
178     }
179   }
180   fflush(stderr);
181 }
182 
PrintException(Isolate * isolate,Local<Context> context,Local<Value> err,Local<Message> message)183 void PrintException(Isolate* isolate,
184                     Local<Context> context,
185                     Local<Value> err,
186                     Local<Message> message) {
187   node::Utf8Value reason(isolate,
188                          err->ToDetailString(context)
189                              .FromMaybe(Local<String>()));
190   bool added_exception_line = false;
191   std::string source =
192       GetErrorSource(isolate, context, message, &added_exception_line);
193   FPrintF(stderr, "%s\n", source);
194   FPrintF(stderr, "%s\n", reason);
195 
196   Local<v8::StackTrace> stack = message->GetStackTrace();
197   if (!stack.IsEmpty()) PrintStackTrace(isolate, stack);
198 }
199 
PrintCaughtException(Isolate * isolate,Local<Context> context,const v8::TryCatch & try_catch)200 void PrintCaughtException(Isolate* isolate,
201                           Local<Context> context,
202                           const v8::TryCatch& try_catch) {
203   CHECK(try_catch.HasCaught());
204   PrintException(isolate, context, try_catch.Exception(), try_catch.Message());
205 }
206 
AppendExceptionLine(Environment * env,Local<Value> er,Local<Message> message,enum ErrorHandlingMode mode)207 void AppendExceptionLine(Environment* env,
208                          Local<Value> er,
209                          Local<Message> message,
210                          enum ErrorHandlingMode mode) {
211   if (message.IsEmpty()) return;
212 
213   HandleScope scope(env->isolate());
214   Local<Object> err_obj;
215   if (!er.IsEmpty() && er->IsObject()) {
216     err_obj = er.As<Object>();
217   }
218 
219   bool added_exception_line = false;
220   std::string source = GetErrorSource(
221       env->isolate(), env->context(), message, &added_exception_line);
222   if (!added_exception_line) {
223     return;
224   }
225   MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
226 
227   const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
228   // If allocating arrow_str failed, print it out. There's not much else to do.
229   // If it's not an error, but something needs to be printed out because
230   // it's a fatal exception, also print it out from here.
231   // Otherwise, the arrow property will be attached to the object and handled
232   // by the caller.
233   if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
234     if (env->printed_error()) return;
235     Mutex::ScopedLock lock(per_process::tty_mutex);
236     env->set_printed_error(true);
237 
238     ResetStdio();
239     FPrintF(stderr, "\n%s", source);
240     return;
241   }
242 
243   CHECK(err_obj
244             ->SetPrivate(env->context(),
245                          env->arrow_message_private_symbol(),
246                          arrow_str.ToLocalChecked())
247             .FromMaybe(false));
248 }
249 
Abort()250 [[noreturn]] void Abort() {
251   DumpBacktrace(stderr);
252   fflush(stderr);
253   ABORT_NO_BACKTRACE();
254 }
255 
Assert(const AssertionInfo & info)256 [[noreturn]] void Assert(const AssertionInfo& info) {
257   std::string name = GetHumanReadableProcessName();
258 
259   fprintf(stderr,
260           "%s: %s:%s%s Assertion `%s' failed.\n",
261           name.c_str(),
262           info.file_line,
263           info.function,
264           *info.function ? ":" : "",
265           info.message);
266   fflush(stderr);
267 
268   Abort();
269 }
270 
271 enum class EnhanceFatalException { kEnhance, kDontEnhance };
272 
273 /**
274  * Report the exception to the inspector, then print it to stderr.
275  * This should only be used when the Node.js instance is about to exit
276  * (i.e. this should be followed by a env->Exit() or an Abort()).
277  *
278  * Use enhance_stack = EnhanceFatalException::kDontEnhance
279  * when it's unsafe to call into JavaScript.
280  */
ReportFatalException(Environment * env,Local<Value> error,Local<Message> message,EnhanceFatalException enhance_stack)281 static void ReportFatalException(Environment* env,
282                                  Local<Value> error,
283                                  Local<Message> message,
284                                  EnhanceFatalException enhance_stack) {
285   if (!env->can_call_into_js())
286     enhance_stack = EnhanceFatalException::kDontEnhance;
287 
288   Isolate* isolate = env->isolate();
289   CHECK(!error.IsEmpty());
290   CHECK(!message.IsEmpty());
291   HandleScope scope(isolate);
292 
293   AppendExceptionLine(env, error, message, FATAL_ERROR);
294 
295   auto report_to_inspector = [&]() {
296 #if HAVE_INSPECTOR
297     env->inspector_agent()->ReportUncaughtException(error, message);
298 #endif
299   };
300 
301   Local<Value> arrow;
302   Local<Value> stack_trace;
303   bool decorated = IsExceptionDecorated(env, error);
304 
305   if (!error->IsObject()) {  // We can only enhance actual errors.
306     report_to_inspector();
307     stack_trace = Undefined(isolate);
308     // If error is not an object, AppendExceptionLine() has already print the
309     // source line and the arrow to stderr.
310     // TODO(joyeecheung): move that side effect out of AppendExceptionLine().
311     // It is done just to preserve the source line as soon as possible.
312   } else {
313     Local<Object> err_obj = error.As<Object>();
314 
315     auto enhance_with = [&](Local<Function> enhancer) {
316       Local<Value> enhanced;
317       Local<Value> argv[] = {err_obj};
318       if (!enhancer.IsEmpty() &&
319           enhancer
320               ->Call(env->context(), Undefined(isolate), arraysize(argv), argv)
321               .ToLocal(&enhanced)) {
322         stack_trace = enhanced;
323       }
324     };
325 
326     switch (enhance_stack) {
327       case EnhanceFatalException::kEnhance: {
328         enhance_with(env->enhance_fatal_stack_before_inspector());
329         report_to_inspector();
330         enhance_with(env->enhance_fatal_stack_after_inspector());
331         break;
332       }
333       case EnhanceFatalException::kDontEnhance: {
334         USE(err_obj->Get(env->context(), env->stack_string())
335                 .ToLocal(&stack_trace));
336         report_to_inspector();
337         break;
338       }
339       default:
340         UNREACHABLE();
341     }
342 
343     arrow =
344         err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
345             .ToLocalChecked();
346   }
347 
348   node::Utf8Value trace(env->isolate(), stack_trace);
349 
350   // range errors have a trace member set to undefined
351   if (trace.length() > 0 && !stack_trace->IsUndefined()) {
352     if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
353       FPrintF(stderr, "%s\n", trace);
354     } else {
355       node::Utf8Value arrow_string(env->isolate(), arrow);
356       FPrintF(stderr, "%s\n%s\n", arrow_string, trace);
357     }
358   } else {
359     // this really only happens for RangeErrors, since they're the only
360     // kind that won't have all this info in the trace, or when non-Error
361     // objects are thrown manually.
362     MaybeLocal<Value> message;
363     MaybeLocal<Value> name;
364 
365     if (error->IsObject()) {
366       Local<Object> err_obj = error.As<Object>();
367       message = err_obj->Get(env->context(), env->message_string());
368       name = err_obj->Get(env->context(), env->name_string());
369     }
370 
371     if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
372         name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
373       // Not an error object. Just print as-is.
374       node::Utf8Value message(env->isolate(), error);
375 
376       FPrintF(stderr, "%s\n",
377               *message ? message.ToString() : "<toString() threw exception>");
378     } else {
379       node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
380       node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());
381 
382       if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
383         FPrintF(stderr, "%s: %s\n", name_string, message_string);
384       } else {
385         node::Utf8Value arrow_string(env->isolate(), arrow);
386         FPrintF(stderr,
387             "%s\n%s: %s\n", arrow_string, name_string, message_string);
388       }
389     }
390 
391     if (!env->options()->trace_uncaught) {
392       std::string argv0;
393       if (!env->argv().empty()) argv0 = env->argv()[0];
394       if (argv0.empty()) argv0 = "node";
395       FPrintF(stderr,
396               "(Use `%s --trace-uncaught ...` to show where the exception "
397               "was thrown)\n",
398               fs::Basename(argv0, ".exe"));
399     }
400   }
401 
402   if (env->options()->trace_uncaught) {
403     Local<StackTrace> trace = message->GetStackTrace();
404     if (!trace.IsEmpty()) {
405       FPrintF(stderr, "Thrown at:\n");
406       PrintStackTrace(env->isolate(), trace);
407     }
408   }
409 
410   fflush(stderr);
411 }
412 
FatalError(const char * location,const char * message)413 [[noreturn]] void FatalError(const char* location, const char* message) {
414   OnFatalError(location, message);
415   // to suppress compiler warning
416   ABORT();
417 }
418 
OnFatalError(const char * location,const char * message)419 void OnFatalError(const char* location, const char* message) {
420   if (location) {
421     FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message);
422   } else {
423     FPrintF(stderr, "FATAL ERROR: %s\n", message);
424   }
425 
426   Isolate* isolate = Isolate::GetCurrent();
427   Environment* env = nullptr;
428   if (isolate != nullptr) {
429     env = Environment::GetCurrent(isolate);
430   }
431   bool report_on_fatalerror;
432   {
433     Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
434     report_on_fatalerror = per_process::cli_options->report_on_fatalerror;
435   }
436 
437   if (report_on_fatalerror) {
438     report::TriggerNodeReport(
439         isolate, env, message, "FatalError", "", Local<Object>());
440   }
441 
442   fflush(stderr);
443   ABORT();
444 }
445 
446 namespace errors {
447 
~TryCatchScope()448 TryCatchScope::~TryCatchScope() {
449   if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
450     HandleScope scope(env_->isolate());
451     Local<v8::Value> exception = Exception();
452     Local<v8::Message> message = Message();
453     EnhanceFatalException enhance = CanContinue() ?
454         EnhanceFatalException::kEnhance : EnhanceFatalException::kDontEnhance;
455     if (message.IsEmpty())
456       message = Exception::CreateMessage(env_->isolate(), exception);
457     ReportFatalException(env_, exception, message, enhance);
458     env_->Exit(7);
459   }
460 }
461 
errno_string(int errorno)462 const char* errno_string(int errorno) {
463 #define ERRNO_CASE(e)                                                          \
464   case e:                                                                      \
465     return #e;
466   switch (errorno) {
467 #ifdef EACCES
468     ERRNO_CASE(EACCES);
469 #endif
470 
471 #ifdef EADDRINUSE
472     ERRNO_CASE(EADDRINUSE);
473 #endif
474 
475 #ifdef EADDRNOTAVAIL
476     ERRNO_CASE(EADDRNOTAVAIL);
477 #endif
478 
479 #ifdef EAFNOSUPPORT
480     ERRNO_CASE(EAFNOSUPPORT);
481 #endif
482 
483 #ifdef EAGAIN
484     ERRNO_CASE(EAGAIN);
485 #endif
486 
487 #ifdef EWOULDBLOCK
488 #if EAGAIN != EWOULDBLOCK
489     ERRNO_CASE(EWOULDBLOCK);
490 #endif
491 #endif
492 
493 #ifdef EALREADY
494     ERRNO_CASE(EALREADY);
495 #endif
496 
497 #ifdef EBADF
498     ERRNO_CASE(EBADF);
499 #endif
500 
501 #ifdef EBADMSG
502     ERRNO_CASE(EBADMSG);
503 #endif
504 
505 #ifdef EBUSY
506     ERRNO_CASE(EBUSY);
507 #endif
508 
509 #ifdef ECANCELED
510     ERRNO_CASE(ECANCELED);
511 #endif
512 
513 #ifdef ECHILD
514     ERRNO_CASE(ECHILD);
515 #endif
516 
517 #ifdef ECONNABORTED
518     ERRNO_CASE(ECONNABORTED);
519 #endif
520 
521 #ifdef ECONNREFUSED
522     ERRNO_CASE(ECONNREFUSED);
523 #endif
524 
525 #ifdef ECONNRESET
526     ERRNO_CASE(ECONNRESET);
527 #endif
528 
529 #ifdef EDEADLK
530     ERRNO_CASE(EDEADLK);
531 #endif
532 
533 #ifdef EDESTADDRREQ
534     ERRNO_CASE(EDESTADDRREQ);
535 #endif
536 
537 #ifdef EDOM
538     ERRNO_CASE(EDOM);
539 #endif
540 
541 #ifdef EDQUOT
542     ERRNO_CASE(EDQUOT);
543 #endif
544 
545 #ifdef EEXIST
546     ERRNO_CASE(EEXIST);
547 #endif
548 
549 #ifdef EFAULT
550     ERRNO_CASE(EFAULT);
551 #endif
552 
553 #ifdef EFBIG
554     ERRNO_CASE(EFBIG);
555 #endif
556 
557 #ifdef EHOSTUNREACH
558     ERRNO_CASE(EHOSTUNREACH);
559 #endif
560 
561 #ifdef EIDRM
562     ERRNO_CASE(EIDRM);
563 #endif
564 
565 #ifdef EILSEQ
566     ERRNO_CASE(EILSEQ);
567 #endif
568 
569 #ifdef EINPROGRESS
570     ERRNO_CASE(EINPROGRESS);
571 #endif
572 
573 #ifdef EINTR
574     ERRNO_CASE(EINTR);
575 #endif
576 
577 #ifdef EINVAL
578     ERRNO_CASE(EINVAL);
579 #endif
580 
581 #ifdef EIO
582     ERRNO_CASE(EIO);
583 #endif
584 
585 #ifdef EISCONN
586     ERRNO_CASE(EISCONN);
587 #endif
588 
589 #ifdef EISDIR
590     ERRNO_CASE(EISDIR);
591 #endif
592 
593 #ifdef ELOOP
594     ERRNO_CASE(ELOOP);
595 #endif
596 
597 #ifdef EMFILE
598     ERRNO_CASE(EMFILE);
599 #endif
600 
601 #ifdef EMLINK
602     ERRNO_CASE(EMLINK);
603 #endif
604 
605 #ifdef EMSGSIZE
606     ERRNO_CASE(EMSGSIZE);
607 #endif
608 
609 #ifdef EMULTIHOP
610     ERRNO_CASE(EMULTIHOP);
611 #endif
612 
613 #ifdef ENAMETOOLONG
614     ERRNO_CASE(ENAMETOOLONG);
615 #endif
616 
617 #ifdef ENETDOWN
618     ERRNO_CASE(ENETDOWN);
619 #endif
620 
621 #ifdef ENETRESET
622     ERRNO_CASE(ENETRESET);
623 #endif
624 
625 #ifdef ENETUNREACH
626     ERRNO_CASE(ENETUNREACH);
627 #endif
628 
629 #ifdef ENFILE
630     ERRNO_CASE(ENFILE);
631 #endif
632 
633 #ifdef ENOBUFS
634     ERRNO_CASE(ENOBUFS);
635 #endif
636 
637 #ifdef ENODATA
638     ERRNO_CASE(ENODATA);
639 #endif
640 
641 #ifdef ENODEV
642     ERRNO_CASE(ENODEV);
643 #endif
644 
645 #ifdef ENOENT
646     ERRNO_CASE(ENOENT);
647 #endif
648 
649 #ifdef ENOEXEC
650     ERRNO_CASE(ENOEXEC);
651 #endif
652 
653 #ifdef ENOLINK
654     ERRNO_CASE(ENOLINK);
655 #endif
656 
657 #ifdef ENOLCK
658 #if ENOLINK != ENOLCK
659     ERRNO_CASE(ENOLCK);
660 #endif
661 #endif
662 
663 #ifdef ENOMEM
664     ERRNO_CASE(ENOMEM);
665 #endif
666 
667 #ifdef ENOMSG
668     ERRNO_CASE(ENOMSG);
669 #endif
670 
671 #ifdef ENOPROTOOPT
672     ERRNO_CASE(ENOPROTOOPT);
673 #endif
674 
675 #ifdef ENOSPC
676     ERRNO_CASE(ENOSPC);
677 #endif
678 
679 #ifdef ENOSR
680     ERRNO_CASE(ENOSR);
681 #endif
682 
683 #ifdef ENOSTR
684     ERRNO_CASE(ENOSTR);
685 #endif
686 
687 #ifdef ENOSYS
688     ERRNO_CASE(ENOSYS);
689 #endif
690 
691 #ifdef ENOTCONN
692     ERRNO_CASE(ENOTCONN);
693 #endif
694 
695 #ifdef ENOTDIR
696     ERRNO_CASE(ENOTDIR);
697 #endif
698 
699 #ifdef ENOTEMPTY
700 #if ENOTEMPTY != EEXIST
701     ERRNO_CASE(ENOTEMPTY);
702 #endif
703 #endif
704 
705 #ifdef ENOTSOCK
706     ERRNO_CASE(ENOTSOCK);
707 #endif
708 
709 #ifdef ENOTSUP
710     ERRNO_CASE(ENOTSUP);
711 #else
712 #ifdef EOPNOTSUPP
713     ERRNO_CASE(EOPNOTSUPP);
714 #endif
715 #endif
716 
717 #ifdef ENOTTY
718     ERRNO_CASE(ENOTTY);
719 #endif
720 
721 #ifdef ENXIO
722     ERRNO_CASE(ENXIO);
723 #endif
724 
725 #ifdef EOVERFLOW
726     ERRNO_CASE(EOVERFLOW);
727 #endif
728 
729 #ifdef EPERM
730     ERRNO_CASE(EPERM);
731 #endif
732 
733 #ifdef EPIPE
734     ERRNO_CASE(EPIPE);
735 #endif
736 
737 #ifdef EPROTO
738     ERRNO_CASE(EPROTO);
739 #endif
740 
741 #ifdef EPROTONOSUPPORT
742     ERRNO_CASE(EPROTONOSUPPORT);
743 #endif
744 
745 #ifdef EPROTOTYPE
746     ERRNO_CASE(EPROTOTYPE);
747 #endif
748 
749 #ifdef ERANGE
750     ERRNO_CASE(ERANGE);
751 #endif
752 
753 #ifdef EROFS
754     ERRNO_CASE(EROFS);
755 #endif
756 
757 #ifdef ESPIPE
758     ERRNO_CASE(ESPIPE);
759 #endif
760 
761 #ifdef ESRCH
762     ERRNO_CASE(ESRCH);
763 #endif
764 
765 #ifdef ESTALE
766     ERRNO_CASE(ESTALE);
767 #endif
768 
769 #ifdef ETIME
770     ERRNO_CASE(ETIME);
771 #endif
772 
773 #ifdef ETIMEDOUT
774     ERRNO_CASE(ETIMEDOUT);
775 #endif
776 
777 #ifdef ETXTBSY
778     ERRNO_CASE(ETXTBSY);
779 #endif
780 
781 #ifdef EXDEV
782     ERRNO_CASE(EXDEV);
783 #endif
784 
785     default:
786       return "";
787   }
788 }
789 
PerIsolateMessageListener(Local<Message> message,Local<Value> error)790 void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
791   Isolate* isolate = message->GetIsolate();
792   switch (message->ErrorLevel()) {
793     case Isolate::MessageErrorLevel::kMessageWarning: {
794       Environment* env = Environment::GetCurrent(isolate);
795       if (!env) {
796         break;
797       }
798       Utf8Value filename(isolate, message->GetScriptOrigin().ResourceName());
799       // (filename):(line) (message)
800       std::stringstream warning;
801       warning << *filename;
802       warning << ":";
803       warning << message->GetLineNumber(env->context()).FromMaybe(-1);
804       warning << " ";
805       v8::String::Utf8Value msg(isolate, message->Get());
806       warning << *msg;
807       USE(ProcessEmitWarningGeneric(env, warning.str().c_str(), "V8"));
808       break;
809     }
810     case Isolate::MessageErrorLevel::kMessageError:
811       TriggerUncaughtException(isolate, error, message);
812       break;
813   }
814 }
815 
SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value> & args)816 void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
817   Environment* env = Environment::GetCurrent(args);
818   CHECK(args[0]->IsFunction());
819   env->set_prepare_stack_trace_callback(args[0].As<Function>());
820 }
821 
SetSourceMapsEnabled(const FunctionCallbackInfo<Value> & args)822 static void SetSourceMapsEnabled(const FunctionCallbackInfo<Value>& args) {
823   Environment* env = Environment::GetCurrent(args);
824   CHECK(args[0]->IsBoolean());
825   env->set_source_maps_enabled(args[0].As<Boolean>()->Value());
826 }
827 
SetEnhanceStackForFatalException(const FunctionCallbackInfo<Value> & args)828 static void SetEnhanceStackForFatalException(
829     const FunctionCallbackInfo<Value>& args) {
830   Environment* env = Environment::GetCurrent(args);
831   CHECK(args[0]->IsFunction());
832   CHECK(args[1]->IsFunction());
833   env->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
834   env->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
835 }
836 
837 // Side effect-free stringification that will never throw exceptions.
NoSideEffectsToString(const FunctionCallbackInfo<Value> & args)838 static void NoSideEffectsToString(const FunctionCallbackInfo<Value>& args) {
839   Local<Context> context = args.GetIsolate()->GetCurrentContext();
840   Local<String> detail_string;
841   if (args[0]->ToDetailString(context).ToLocal(&detail_string))
842     args.GetReturnValue().Set(detail_string);
843 }
844 
TriggerUncaughtException(const FunctionCallbackInfo<Value> & args)845 static void TriggerUncaughtException(const FunctionCallbackInfo<Value>& args) {
846   Isolate* isolate = args.GetIsolate();
847   Environment* env = Environment::GetCurrent(isolate);
848   Local<Value> exception = args[0];
849   Local<Message> message = Exception::CreateMessage(isolate, exception);
850   if (env != nullptr && env->abort_on_uncaught_exception()) {
851     ReportFatalException(
852         env, exception, message, EnhanceFatalException::kEnhance);
853     Abort();
854   }
855   bool from_promise = args[1]->IsTrue();
856   errors::TriggerUncaughtException(isolate, exception, message, from_promise);
857 }
858 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)859 void Initialize(Local<Object> target,
860                 Local<Value> unused,
861                 Local<Context> context,
862                 void* priv) {
863   Environment* env = Environment::GetCurrent(context);
864   env->SetMethod(
865       target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
866   env->SetMethod(target, "setSourceMapsEnabled", SetSourceMapsEnabled);
867   env->SetMethod(target,
868                  "setEnhanceStackForFatalException",
869                  SetEnhanceStackForFatalException);
870   env->SetMethodNoSideEffect(
871       target, "noSideEffectsToString", NoSideEffectsToString);
872   env->SetMethod(target, "triggerUncaughtException", TriggerUncaughtException);
873 }
874 
DecorateErrorStack(Environment * env,const errors::TryCatchScope & try_catch)875 void DecorateErrorStack(Environment* env,
876                         const errors::TryCatchScope& try_catch) {
877   Local<Value> exception = try_catch.Exception();
878 
879   if (!exception->IsObject()) return;
880 
881   Local<Object> err_obj = exception.As<Object>();
882 
883   if (IsExceptionDecorated(env, err_obj)) return;
884 
885   AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
886   TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
887   MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
888   MaybeLocal<Value> maybe_value =
889       err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
890 
891   Local<Value> arrow;
892   if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
893     return;
894   }
895 
896   if (stack.IsEmpty() || !stack.ToLocalChecked()->IsString()) {
897     return;
898   }
899 
900   Local<String> decorated_stack = String::Concat(
901       env->isolate(),
902       String::Concat(env->isolate(),
903                      arrow.As<String>(),
904                      FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
905       stack.ToLocalChecked().As<String>());
906   USE(err_obj->Set(env->context(), env->stack_string(), decorated_stack));
907   err_obj->SetPrivate(
908       env->context(), env->decorated_private_symbol(), True(env->isolate()));
909 }
910 
TriggerUncaughtException(Isolate * isolate,Local<Value> error,Local<Message> message,bool from_promise)911 void TriggerUncaughtException(Isolate* isolate,
912                               Local<Value> error,
913                               Local<Message> message,
914                               bool from_promise) {
915   CHECK(!error.IsEmpty());
916   HandleScope scope(isolate);
917 
918   if (message.IsEmpty()) message = Exception::CreateMessage(isolate, error);
919 
920   CHECK(isolate->InContext());
921   Local<Context> context = isolate->GetCurrentContext();
922   Environment* env = Environment::GetCurrent(context);
923   if (env == nullptr) {
924     // This means that the exception happens before Environment is assigned
925     // to the context e.g. when there is a SyntaxError in a per-context
926     // script - which usually indicates that there is a bug because no JS
927     // error is supposed to be thrown at this point.
928     // Since we don't have access to Environment here, there is not
929     // much we can do, so we just print whatever is useful and crash.
930     PrintException(isolate, context, error, message);
931     Abort();
932   }
933 
934   // Invoke process._fatalException() to give user a chance to handle it.
935   // We have to grab it from the process object since this has been
936   // monkey-patchable.
937   Local<Object> process_object = env->process_object();
938   Local<String> fatal_exception_string = env->fatal_exception_string();
939   Local<Value> fatal_exception_function =
940       process_object->Get(env->context(),
941                           fatal_exception_string).ToLocalChecked();
942   // If the exception happens before process._fatalException is attached
943   // during bootstrap, or if the user has patched it incorrectly, exit
944   // the current Node.js instance.
945   if (!fatal_exception_function->IsFunction()) {
946     ReportFatalException(
947         env, error, message, EnhanceFatalException::kDontEnhance);
948     env->Exit(6);
949     return;
950   }
951 
952   MaybeLocal<Value> maybe_handled;
953   if (env->can_call_into_js()) {
954     // We do not expect the global uncaught exception itself to throw any more
955     // exceptions. If it does, exit the current Node.js instance.
956     errors::TryCatchScope try_catch(env,
957                                     errors::TryCatchScope::CatchMode::kFatal);
958     // Explicitly disable verbose exception reporting -
959     // if process._fatalException() throws an error, we don't want it to
960     // trigger the per-isolate message listener which will call this
961     // function and recurse.
962     try_catch.SetVerbose(false);
963     Local<Value> argv[2] = { error,
964                              Boolean::New(env->isolate(), from_promise) };
965 
966     maybe_handled = fatal_exception_function.As<Function>()->Call(
967         env->context(), process_object, arraysize(argv), argv);
968   }
969 
970   // If process._fatalException() throws, we are now exiting the Node.js
971   // instance so return to continue the exit routine.
972   // TODO(joyeecheung): return a Maybe here to prevent the caller from
973   // stepping on the exit.
974   Local<Value> handled;
975   if (!maybe_handled.ToLocal(&handled)) {
976     return;
977   }
978 
979   // The global uncaught exception handler returns true if the user handles it
980   // by e.g. listening to `uncaughtException`. In that case, continue program
981   // execution.
982   // TODO(joyeecheung): This has been only checking that the return value is
983   // exactly false. Investigate whether this can be turned to an "if true"
984   // similar to how the worker global uncaught exception handler handles it.
985   if (!handled->IsFalse()) {
986     return;
987   }
988 
989   // Now we are certain that the exception is fatal.
990   ReportFatalException(env, error, message, EnhanceFatalException::kEnhance);
991   RunAtExit(env);
992 
993   // If the global uncaught exception handler sets process.exitCode,
994   // exit with that code. Otherwise, exit with 1.
995   Local<String> exit_code = env->exit_code_string();
996   Local<Value> code;
997   if (process_object->Get(env->context(), exit_code).ToLocal(&code) &&
998       code->IsInt32()) {
999     env->Exit(code.As<Int32>()->Value());
1000   } else {
1001     env->Exit(1);
1002   }
1003 }
1004 
TriggerUncaughtException(Isolate * isolate,const v8::TryCatch & try_catch)1005 void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {
1006   // If the try_catch is verbose, the per-isolate message listener is going to
1007   // handle it (which is going to call into another overload of
1008   // TriggerUncaughtException()).
1009   if (try_catch.IsVerbose()) {
1010     return;
1011   }
1012 
1013   // If the user calls TryCatch::TerminateExecution() on this TryCatch
1014   // they must call CancelTerminateExecution() again before invoking
1015   // TriggerUncaughtException() because it will invoke
1016   // process._fatalException() in the JS land.
1017   CHECK(!try_catch.HasTerminated());
1018   CHECK(try_catch.HasCaught());
1019   HandleScope scope(isolate);
1020   TriggerUncaughtException(isolate,
1021                            try_catch.Exception(),
1022                            try_catch.Message(),
1023                            false /* from_promise */);
1024 }
1025 
1026 }  // namespace errors
1027 
1028 }  // namespace node
1029 
1030 NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)
1031