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