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