GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_errors.cc Lines: 347 490 70.8 %
Date: 2022-11-20 04:28:36 Branches: 195 365 53.4 %

Line Branch Exec Source
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
37
598
bool IsExceptionDecorated(Environment* env, Local<Value> er) {
38

1196
  if (!er.IsEmpty() && er->IsObject()) {
39
583
    Local<Object> err_obj = er.As<Object>();
40
    auto maybe_value =
41
583
        err_obj->GetPrivate(env->context(), env->decorated_private_symbol());
42
    Local<Value> decorated;
43

1166
    return maybe_value.ToLocal(&decorated) && decorated->IsTrue();
44
  }
45
15
  return false;
46
}
47
48
namespace per_process {
49
static Mutex tty_mutex;
50
}  // namespace per_process
51
52
17
static std::string GetSourceMapErrorSource(Isolate* isolate,
53
                                           Local<Context> context,
54
                                           Local<Message> message,
55
                                           bool* added_exception_line) {
56
34
  v8::TryCatch try_catch(isolate);
57
34
  HandleScope handle_scope(isolate);
58
17
  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
17
  Local<Value> script_resource_name = message->GetScriptResourceName();
64
34
  int linenum = message->GetLineNumber(context).FromJust();
65
17
  int columnum = message->GetStartColumn(context).FromJust();
66
67
  Local<Value> argv[] = {script_resource_name,
68
                         v8::Int32::New(isolate, linenum),
69
34
                         v8::Int32::New(isolate, columnum)};
70
17
  MaybeLocal<Value> maybe_ret = env->get_source_map_error_source()->Call(
71
34
      context, Undefined(isolate), arraysize(argv), argv);
72
  Local<Value> ret;
73
17
  if (!maybe_ret.ToLocal(&ret)) {
74
    // Ignore the caught exceptions.
75
    DCHECK(try_catch.HasCaught());
76
    return std::string();
77
  }
78
34
  if (!ret->IsString()) {
79
1
    return std::string();
80
  }
81
16
  *added_exception_line = true;
82
16
  node::Utf8Value error_source_utf8(isolate, ret.As<String>());
83
16
  return *error_source_utf8;
84
}
85
86
971
static std::string GetErrorSource(Isolate* isolate,
87
                                  Local<Context> context,
88
                                  Local<Message> message,
89
                                  bool* added_exception_line) {
90
971
  MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
91
1942
  node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
92
1942
  std::string sourceline(*encoded_source, encoded_source.length());
93
971
  *added_exception_line = false;
94
95
971
  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
971
  Environment* env = Environment::GetCurrent(isolate);
102
  const bool has_source_map_url =
103
2913
      !message->GetScriptOrigin().SourceMapUrl().IsEmpty() &&
104
2913
      !message->GetScriptOrigin().SourceMapUrl()->IsUndefined();
105


971
  if (has_source_map_url && env != nullptr && env->source_maps_enabled()) {
106
    std::string source = GetSourceMapErrorSource(
107
17
        isolate, context, message, added_exception_line);
108
17
    if (*added_exception_line) {
109
16
      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
955
  ScriptOrigin origin = message->GetScriptOrigin();
136
1910
  node::Utf8Value filename(isolate, message->GetScriptResourceName());
137
955
  const char* filename_string = *filename;
138
955
  int linenum = message->GetLineNumber(context).FromJust();
139
140
955
  int script_start = (linenum - origin.LineOffset()) == 1
141
1120
                         ? origin.ColumnOffset()
142
955
                         : 0;
143
1910
  int start = message->GetStartColumn(context).FromMaybe(0);
144
955
  int end = message->GetEndColumn(context).FromMaybe(0);
145
955
  if (start >= script_start) {
146
954
    CHECK_GE(end, start);
147
954
    start -= script_start;
148
954
    end -= script_start;
149
  }
150
151
  std::string buf = SPrintF("%s:%i\n%s\n",
152
                            filename_string,
153
                            linenum,
154
1910
                            sourceline.c_str());
155
955
  CHECK_GT(buf.size(), 0);
156
955
  *added_exception_line = true;
157
158
2865
  if (start > end ||
159


1909
      start < 0 ||
160
954
      static_cast<size_t>(end) > sourceline.size()) {
161
18
    return buf;
162
  }
163
164
937
  constexpr int kUnderlineBufsize = 1020;
165
  char underline_buf[kUnderlineBufsize + 4];
166
937
  int off = 0;
167
  // Print wavy underline (GetUnderline is deprecated).
168
5503
  for (int i = 0; i < start; i++) {
169

4566
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
170
      break;
171
    }
172
4566
    CHECK_LT(off, kUnderlineBufsize);
173
4566
    underline_buf[off++] = (sourceline[i] == '\t') ? '\t' : ' ';
174
  }
175
3561
  for (int i = start; i < end; i++) {
176

2624
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
177
      break;
178
    }
179
2624
    CHECK_LT(off, kUnderlineBufsize);
180
2624
    underline_buf[off++] = '^';
181
  }
182
937
  CHECK_LE(off, kUnderlineBufsize);
183
937
  underline_buf[off++] = '\n';
184
185
937
  return buf + std::string(underline_buf, off);
186
}
187
188
7
void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) {
189
110
  for (int i = 0; i < stack->GetFrameCount(); i++) {
190
48
    Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
191
96
    node::Utf8Value fn_name_s(isolate, stack_frame->GetFunctionName());
192
96
    node::Utf8Value script_name(isolate, stack_frame->GetScriptName());
193
48
    const int line_number = stack_frame->GetLineNumber();
194
48
    const int column = stack_frame->GetColumn();
195
196
48
    if (stack_frame->IsEval()) {
197
      if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
198
        FPrintF(stderr, "    at [eval]:%i:%i\n", line_number, column);
199
      } else {
200
        FPrintF(stderr,
201
                "    at [eval] (%s:%i:%i)\n",
202
                *script_name,
203
                line_number,
204
                column);
205
      }
206
      break;
207
    }
208
209
48
    if (fn_name_s.length() == 0) {
210
19
      FPrintF(stderr, "    at %s:%i:%i\n", script_name, line_number, column);
211
    } else {
212
29
      FPrintF(stderr,
213
              "    at %s (%s:%i:%i)\n",
214
              fn_name_s,
215
              script_name,
216
              line_number,
217
              column);
218
    }
219
  }
220
7
  fflush(stderr);
221
7
}
222
223
424
void PrintException(Isolate* isolate,
224
                    Local<Context> context,
225
                    Local<Value> err,
226
                    Local<Message> message) {
227
  node::Utf8Value reason(isolate,
228
424
                         err->ToDetailString(context)
229
848
                             .FromMaybe(Local<String>()));
230
424
  bool added_exception_line = false;
231
  std::string source =
232
848
      GetErrorSource(isolate, context, message, &added_exception_line);
233
424
  FPrintF(stderr, "%s\n", source);
234
424
  FPrintF(stderr, "%s\n", reason);
235
236
424
  Local<v8::StackTrace> stack = message->GetStackTrace();
237
424
  if (!stack.IsEmpty()) PrintStackTrace(isolate, stack);
238
424
}
239
240
424
void PrintCaughtException(Isolate* isolate,
241
                          Local<Context> context,
242
                          const v8::TryCatch& try_catch) {
243
424
  CHECK(try_catch.HasCaught());
244
424
  PrintException(isolate, context, try_catch.Exception(), try_catch.Message());
245
424
}
246
247
616
void AppendExceptionLine(Environment* env,
248
                         Local<Value> er,
249
                         Local<Message> message,
250
                         enum ErrorHandlingMode mode) {
251
707
  if (message.IsEmpty()) return;
252
253
616
  HandleScope scope(env->isolate());
254
  Local<Object> err_obj;
255

1232
  if (!er.IsEmpty() && er->IsObject()) {
256
601
    err_obj = er.As<Object>();
257
    // If arrow_message is already set, skip.
258
    auto maybe_value = err_obj->GetPrivate(env->context(),
259
601
                                          env->arrow_message_private_symbol());
260
    Local<Value> lvalue;
261

1803
    if (!maybe_value.ToLocal(&lvalue) || lvalue->IsString())
262
69
      return;
263
  }
264
265
547
  bool added_exception_line = false;
266
  std::string source = GetErrorSource(
267
547
      env->isolate(), env->context(), message, &added_exception_line);
268
547
  if (!added_exception_line) {
269
    return;
270
  }
271
547
  MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
272
273

1094
  const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
274
  // If allocating arrow_str failed, print it out. There's not much else to do.
275
  // If it's not an error, but something needs to be printed out because
276
  // it's a fatal exception, also print it out from here.
277
  // Otherwise, the arrow property will be attached to the object and handled
278
  // by the caller.
279


761
  if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
280
22
    if (env->printed_error()) return;
281
22
    Mutex::ScopedLock lock(per_process::tty_mutex);
282
22
    env->set_printed_error(true);
283
284
22
    ResetStdio();
285
22
    FPrintF(stderr, "\n%s", source);
286
22
    return;
287
  }
288
289

1575
  CHECK(err_obj
290
            ->SetPrivate(env->context(),
291
                         env->arrow_message_private_symbol(),
292
                         arrow_str.ToLocalChecked())
293
            .FromMaybe(false));
294
}
295
296
[[noreturn]] void Abort() {
297
  DumpBacktrace(stderr);
298
  fflush(stderr);
299
  ABORT_NO_BACKTRACE();
300
}
301
302
[[noreturn]] void Assert(const AssertionInfo& info) {
303
  std::string name = GetHumanReadableProcessName();
304
305
  fprintf(stderr,
306
          "%s: %s:%s%s Assertion `%s' failed.\n",
307
          name.c_str(),
308
          info.file_line,
309
          info.function,
310
          *info.function ? ":" : "",
311
          info.message);
312
  fflush(stderr);
313
314
  Abort();
315
}
316
317
enum class EnhanceFatalException { kEnhance, kDontEnhance };
318
319
/**
320
 * Report the exception to the inspector, then print it to stderr.
321
 * This should only be used when the Node.js instance is about to exit
322
 * (i.e. this should be followed by a env->Exit() or an Abort()).
323
 *
324
 * Use enhance_stack = EnhanceFatalException::kDontEnhance
325
 * when it's unsafe to call into JavaScript.
326
 */
327
298
static void ReportFatalException(Environment* env,
328
                                 Local<Value> error,
329
                                 Local<Message> message,
330
                                 EnhanceFatalException enhance_stack) {
331
298
  if (!env->can_call_into_js())
332
    enhance_stack = EnhanceFatalException::kDontEnhance;
333
334
298
  Isolate* isolate = env->isolate();
335
298
  CHECK(!error.IsEmpty());
336
298
  CHECK(!message.IsEmpty());
337
596
  HandleScope scope(isolate);
338
339
298
  AppendExceptionLine(env, error, message, FATAL_ERROR);
340
341
298
  auto report_to_inspector = [&]() {
342
#if HAVE_INSPECTOR
343
298
    env->inspector_agent()->ReportUncaughtException(error, message);
344
#endif
345
298
  };
346
347
  Local<Value> arrow;
348
  Local<Value> stack_trace;
349
298
  bool decorated = IsExceptionDecorated(env, error);
350
351
298
  if (!error->IsObject()) {  // We can only enhance actual errors.
352
15
    report_to_inspector();
353
30
    stack_trace = Undefined(isolate);
354
    // If error is not an object, AppendExceptionLine() has already print the
355
    // source line and the arrow to stderr.
356
    // TODO(joyeecheung): move that side effect out of AppendExceptionLine().
357
    // It is done just to preserve the source line as soon as possible.
358
  } else {
359
283
    Local<Object> err_obj = error.As<Object>();
360
361
562
    auto enhance_with = [&](Local<Function> enhancer) {
362
      Local<Value> enhanced;
363
562
      Local<Value> argv[] = {err_obj};
364
1124
      if (!enhancer.IsEmpty() &&
365
          enhancer
366
1686
              ->Call(env->context(), Undefined(isolate), arraysize(argv), argv)
367
562
              .ToLocal(&enhanced)) {
368
558
        stack_trace = enhanced;
369
      }
370
845
    };
371
372
283
    switch (enhance_stack) {
373
281
      case EnhanceFatalException::kEnhance: {
374
281
        enhance_with(env->enhance_fatal_stack_before_inspector());
375
281
        report_to_inspector();
376
281
        enhance_with(env->enhance_fatal_stack_after_inspector());
377
281
        break;
378
      }
379
2
      case EnhanceFatalException::kDontEnhance: {
380
4
        USE(err_obj->Get(env->context(), env->stack_string())
381
2
                .ToLocal(&stack_trace));
382
2
        report_to_inspector();
383
2
        break;
384
      }
385
      default:
386
        UNREACHABLE();
387
    }
388
389
    arrow =
390
283
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
391
283
            .ToLocalChecked();
392
  }
393
394
596
  node::Utf8Value trace(env->isolate(), stack_trace);
395
596
  std::string report_message = "Exception";
396
397
  // range errors have a trace member set to undefined
398

890
  if (trace.length() > 0 && !stack_trace->IsUndefined()) {
399


843
    if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
400
67
      FPrintF(stderr, "%s\n", trace);
401
    } else {
402
428
      node::Utf8Value arrow_string(env->isolate(), arrow);
403
214
      FPrintF(stderr, "%s\n%s\n", arrow_string, trace);
404
    }
405
  } else {
406
    // this really only happens for RangeErrors, since they're the only
407
    // kind that won't have all this info in the trace, or when non-Error
408
    // objects are thrown manually.
409
    MaybeLocal<Value> message;
410
    MaybeLocal<Value> name;
411
412
17
    if (error->IsObject()) {
413
2
      Local<Object> err_obj = error.As<Object>();
414
4
      message = err_obj->Get(env->context(), env->message_string());
415
4
      name = err_obj->Get(env->context(), env->name_string());
416
    }
417
418
4
    if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
419


19
        name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
420
      // Not an error object. Just print as-is.
421
17
      node::Utf8Value message(env->isolate(), error);
422
423
17
      FPrintF(stderr, "%s\n",
424

34
              *message ? message.ToString() : "<toString() threw exception>");
425
    } else {
426
      node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
427
      node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());
428
      // Update the report message if it is an object has message property.
429
      report_message = message_string.ToString();
430
431
      if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
432
        FPrintF(stderr, "%s: %s\n", name_string, message_string);
433
      } else {
434
        node::Utf8Value arrow_string(env->isolate(), arrow);
435
        FPrintF(stderr,
436
            "%s\n%s: %s\n", arrow_string, name_string, message_string);
437
      }
438
    }
439
440
17
    if (!env->options()->trace_uncaught) {
441
14
      std::string argv0;
442
14
      if (!env->argv().empty()) argv0 = env->argv()[0];
443
14
      if (argv0.empty()) argv0 = "node";
444
14
      FPrintF(stderr,
445
              "(Use `%s --trace-uncaught ...` to show where the exception "
446
              "was thrown)\n",
447
28
              fs::Basename(argv0, ".exe"));
448
    }
449
  }
450
451
298
  if (env->isolate_data()->options()->report_uncaught_exception) {
452
4
    TriggerNodeReport(env, report_message.c_str(), "Exception", "", error);
453
  }
454
455
298
  if (env->options()->trace_uncaught) {
456
3
    Local<StackTrace> trace = message->GetStackTrace();
457
3
    if (!trace.IsEmpty()) {
458
3
      FPrintF(stderr, "Thrown at:\n");
459
3
      PrintStackTrace(env->isolate(), trace);
460
    }
461
  }
462
463
298
  if (env->options()->extra_info_on_fatal_exception) {
464
297
    FPrintF(stderr, "\nNode.js %s\n", NODE_VERSION);
465
  }
466
467
298
  fflush(stderr);
468
298
}
469
470
[[noreturn]] void FatalError(const char* location, const char* message) {
471
  OnFatalError(location, message);
472
  // to suppress compiler warning
473
  ABORT();
474
}
475
476
void OnFatalError(const char* location, const char* message) {
477
  if (location) {
478
    FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message);
479
  } else {
480
    FPrintF(stderr, "FATAL ERROR: %s\n", message);
481
  }
482
483
  Isolate* isolate = Isolate::TryGetCurrent();
484
  bool report_on_fatalerror;
485
  {
486
    Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
487
    report_on_fatalerror = per_process::cli_options->report_on_fatalerror;
488
  }
489
490
  if (report_on_fatalerror) {
491
    TriggerNodeReport(isolate, message, "FatalError", "", Local<Object>());
492
  }
493
494
  fflush(stderr);
495
  ABORT();
496
}
497
498
void OOMErrorHandler(const char* location, const v8::OOMDetails& details) {
499
  const char* message =
500
      details.is_heap_oom ? "Allocation failed - JavaScript heap out of memory"
501
                          : "Allocation failed - process out of memory";
502
  if (location) {
503
    FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message);
504
  } else {
505
    FPrintF(stderr, "FATAL ERROR: %s\n", message);
506
  }
507
508
  Isolate* isolate = Isolate::TryGetCurrent();
509
  bool report_on_fatalerror;
510
  {
511
    Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
512
    report_on_fatalerror = per_process::cli_options->report_on_fatalerror;
513
  }
514
515
  if (report_on_fatalerror) {
516
    // Trigger report with the isolate. Environment::GetCurrent may return
517
    // nullptr here:
518
    // - If the OOM is reported by a young generation space allocation,
519
    //   Isolate::GetCurrentContext returns an empty handle.
520
    // - Otherwise, Isolate::GetCurrentContext returns a non-empty handle.
521
    TriggerNodeReport(isolate, message, "OOMError", "", Local<Object>());
522
  }
523
524
  fflush(stderr);
525
  ABORT();
526
}
527
528
2988
v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
529
    v8::Local<v8::Context> context,
530
    v8::Local<v8::Value> source,
531
    bool is_code_like) {
532
5976
  HandleScope scope(context->GetIsolate());
533
534
2988
  Environment* env = Environment::GetCurrent(context);
535
2988
  if (env->source_maps_enabled()) {
536
    // We do not expect the maybe_cache_generated_source_map to throw any more
537
    // exceptions. If it does, just ignore it.
538
4
    errors::TryCatchScope try_catch(env);
539
    Local<Function> maybe_cache_source_map =
540
2
        env->maybe_cache_generated_source_map();
541
2
    Local<Value> argv[1] = {source};
542
543
    MaybeLocal<Value> maybe_cached = maybe_cache_source_map->Call(
544
4
        context, context->Global(), arraysize(argv), argv);
545
2
    if (maybe_cached.IsEmpty()) {
546
      DCHECK(try_catch.HasCaught());
547
    }
548
  }
549
550
  Local<Value> allow_code_gen = context->GetEmbedderData(
551
5976
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings);
552
  bool codegen_allowed =
553

8964
      allow_code_gen->IsUndefined() || allow_code_gen->IsTrue();
554
  return {
555
      codegen_allowed,
556
      {},
557
2988
  };
558
}
559
560
namespace errors {
561
562
1128494
TryCatchScope::~TryCatchScope() {
563


1128500
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
564
6
    HandleScope scope(env_->isolate());
565
6
    Local<v8::Value> exception = Exception();
566
6
    Local<v8::Message> message = Message();
567
6
    EnhanceFatalException enhance = CanContinue() ?
568
6
        EnhanceFatalException::kEnhance : EnhanceFatalException::kDontEnhance;
569
6
    if (message.IsEmpty())
570
      message = Exception::CreateMessage(env_->isolate(), exception);
571
6
    ReportFatalException(env_, exception, message, enhance);
572
6
    env_->Exit(ExitCode::kExceptionInFatalExceptionHandler);
573
  }
574
1128494
}
575
576
12
const char* errno_string(int errorno) {
577
#define ERRNO_CASE(e)                                                          \
578
  case e:                                                                      \
579
    return #e;
580



















12
  switch (errorno) {
581
#ifdef EACCES
582
    ERRNO_CASE(EACCES);
583
#endif
584
585
#ifdef EADDRINUSE
586
    ERRNO_CASE(EADDRINUSE);
587
#endif
588
589
#ifdef EADDRNOTAVAIL
590
    ERRNO_CASE(EADDRNOTAVAIL);
591
#endif
592
593
#ifdef EAFNOSUPPORT
594
    ERRNO_CASE(EAFNOSUPPORT);
595
#endif
596
597
#ifdef EAGAIN
598
    ERRNO_CASE(EAGAIN);
599
#endif
600
601
#ifdef EWOULDBLOCK
602
#if EAGAIN != EWOULDBLOCK
603
    ERRNO_CASE(EWOULDBLOCK);
604
#endif
605
#endif
606
607
#ifdef EALREADY
608
    ERRNO_CASE(EALREADY);
609
#endif
610
611
#ifdef EBADF
612
    ERRNO_CASE(EBADF);
613
#endif
614
615
#ifdef EBADMSG
616
    ERRNO_CASE(EBADMSG);
617
#endif
618
619
#ifdef EBUSY
620
    ERRNO_CASE(EBUSY);
621
#endif
622
623
#ifdef ECANCELED
624
    ERRNO_CASE(ECANCELED);
625
#endif
626
627
#ifdef ECHILD
628
1
    ERRNO_CASE(ECHILD);
629
#endif
630
631
#ifdef ECONNABORTED
632
    ERRNO_CASE(ECONNABORTED);
633
#endif
634
635
#ifdef ECONNREFUSED
636
    ERRNO_CASE(ECONNREFUSED);
637
#endif
638
639
#ifdef ECONNRESET
640
    ERRNO_CASE(ECONNRESET);
641
#endif
642
643
#ifdef EDEADLK
644
    ERRNO_CASE(EDEADLK);
645
#endif
646
647
#ifdef EDESTADDRREQ
648
    ERRNO_CASE(EDESTADDRREQ);
649
#endif
650
651
#ifdef EDOM
652
    ERRNO_CASE(EDOM);
653
#endif
654
655
#ifdef EDQUOT
656
    ERRNO_CASE(EDQUOT);
657
#endif
658
659
#ifdef EEXIST
660
    ERRNO_CASE(EEXIST);
661
#endif
662
663
#ifdef EFAULT
664
    ERRNO_CASE(EFAULT);
665
#endif
666
667
#ifdef EFBIG
668
    ERRNO_CASE(EFBIG);
669
#endif
670
671
#ifdef EHOSTUNREACH
672
    ERRNO_CASE(EHOSTUNREACH);
673
#endif
674
675
#ifdef EIDRM
676
    ERRNO_CASE(EIDRM);
677
#endif
678
679
#ifdef EILSEQ
680
    ERRNO_CASE(EILSEQ);
681
#endif
682
683
#ifdef EINPROGRESS
684
    ERRNO_CASE(EINPROGRESS);
685
#endif
686
687
#ifdef EINTR
688
    ERRNO_CASE(EINTR);
689
#endif
690
691
#ifdef EINVAL
692
    ERRNO_CASE(EINVAL);
693
#endif
694
695
#ifdef EIO
696
    ERRNO_CASE(EIO);
697
#endif
698
699
#ifdef EISCONN
700
    ERRNO_CASE(EISCONN);
701
#endif
702
703
#ifdef EISDIR
704
    ERRNO_CASE(EISDIR);
705
#endif
706
707
#ifdef ELOOP
708
    ERRNO_CASE(ELOOP);
709
#endif
710
711
#ifdef EMFILE
712
    ERRNO_CASE(EMFILE);
713
#endif
714
715
#ifdef EMLINK
716
    ERRNO_CASE(EMLINK);
717
#endif
718
719
#ifdef EMSGSIZE
720
    ERRNO_CASE(EMSGSIZE);
721
#endif
722
723
#ifdef EMULTIHOP
724
    ERRNO_CASE(EMULTIHOP);
725
#endif
726
727
#ifdef ENAMETOOLONG
728
    ERRNO_CASE(ENAMETOOLONG);
729
#endif
730
731
#ifdef ENETDOWN
732
    ERRNO_CASE(ENETDOWN);
733
#endif
734
735
#ifdef ENETRESET
736
    ERRNO_CASE(ENETRESET);
737
#endif
738
739
#ifdef ENETUNREACH
740
    ERRNO_CASE(ENETUNREACH);
741
#endif
742
743
#ifdef ENFILE
744
    ERRNO_CASE(ENFILE);
745
#endif
746
747
#ifdef ENOBUFS
748
    ERRNO_CASE(ENOBUFS);
749
#endif
750
751
#ifdef ENODATA
752
    ERRNO_CASE(ENODATA);
753
#endif
754
755
#ifdef ENODEV
756
    ERRNO_CASE(ENODEV);
757
#endif
758
759
#ifdef ENOENT
760
    ERRNO_CASE(ENOENT);
761
#endif
762
763
#ifdef ENOEXEC
764
    ERRNO_CASE(ENOEXEC);
765
#endif
766
767
#ifdef ENOLINK
768
    ERRNO_CASE(ENOLINK);
769
#endif
770
771
#ifdef ENOLCK
772
#if ENOLINK != ENOLCK
773
    ERRNO_CASE(ENOLCK);
774
#endif
775
#endif
776
777
#ifdef ENOMEM
778
    ERRNO_CASE(ENOMEM);
779
#endif
780
781
#ifdef ENOMSG
782
    ERRNO_CASE(ENOMSG);
783
#endif
784
785
#ifdef ENOPROTOOPT
786
    ERRNO_CASE(ENOPROTOOPT);
787
#endif
788
789
#ifdef ENOSPC
790
    ERRNO_CASE(ENOSPC);
791
#endif
792
793
#ifdef ENOSR
794
    ERRNO_CASE(ENOSR);
795
#endif
796
797
#ifdef ENOSTR
798
    ERRNO_CASE(ENOSTR);
799
#endif
800
801
#ifdef ENOSYS
802
    ERRNO_CASE(ENOSYS);
803
#endif
804
805
#ifdef ENOTCONN
806
    ERRNO_CASE(ENOTCONN);
807
#endif
808
809
#ifdef ENOTDIR
810
    ERRNO_CASE(ENOTDIR);
811
#endif
812
813
#ifdef ENOTEMPTY
814
#if ENOTEMPTY != EEXIST
815
    ERRNO_CASE(ENOTEMPTY);
816
#endif
817
#endif
818
819
#ifdef ENOTSOCK
820
    ERRNO_CASE(ENOTSOCK);
821
#endif
822
823
#ifdef ENOTSUP
824
    ERRNO_CASE(ENOTSUP);
825
#else
826
#ifdef EOPNOTSUPP
827
    ERRNO_CASE(EOPNOTSUPP);
828
#endif
829
#endif
830
831
#ifdef ENOTTY
832
    ERRNO_CASE(ENOTTY);
833
#endif
834
835
#ifdef ENXIO
836
    ERRNO_CASE(ENXIO);
837
#endif
838
839
#ifdef EOVERFLOW
840
    ERRNO_CASE(EOVERFLOW);
841
#endif
842
843
#ifdef EPERM
844
10
    ERRNO_CASE(EPERM);
845
#endif
846
847
#ifdef EPIPE
848
    ERRNO_CASE(EPIPE);
849
#endif
850
851
#ifdef EPROTO
852
    ERRNO_CASE(EPROTO);
853
#endif
854
855
#ifdef EPROTONOSUPPORT
856
    ERRNO_CASE(EPROTONOSUPPORT);
857
#endif
858
859
#ifdef EPROTOTYPE
860
    ERRNO_CASE(EPROTOTYPE);
861
#endif
862
863
#ifdef ERANGE
864
    ERRNO_CASE(ERANGE);
865
#endif
866
867
#ifdef EROFS
868
    ERRNO_CASE(EROFS);
869
#endif
870
871
#ifdef ESPIPE
872
    ERRNO_CASE(ESPIPE);
873
#endif
874
875
#ifdef ESRCH
876
1
    ERRNO_CASE(ESRCH);
877
#endif
878
879
#ifdef ESTALE
880
    ERRNO_CASE(ESTALE);
881
#endif
882
883
#ifdef ETIME
884
    ERRNO_CASE(ETIME);
885
#endif
886
887
#ifdef ETIMEDOUT
888
    ERRNO_CASE(ETIMEDOUT);
889
#endif
890
891
#ifdef ETXTBSY
892
    ERRNO_CASE(ETXTBSY);
893
#endif
894
895
#ifdef EXDEV
896
    ERRNO_CASE(EXDEV);
897
#endif
898
899
    default:
900
      return "";
901
  }
902
}
903
904
1472
void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
905
1472
  Isolate* isolate = message->GetIsolate();
906
1472
  switch (message->ErrorLevel()) {
907
1
    case Isolate::MessageErrorLevel::kMessageWarning: {
908
1
      Environment* env = Environment::GetCurrent(isolate);
909
1
      if (!env) {
910
        break;
911
      }
912
3
      Utf8Value filename(isolate, message->GetScriptOrigin().ResourceName());
913
      // (filename):(line) (message)
914
2
      std::stringstream warning;
915
1
      warning << *filename;
916
1
      warning << ":";
917
2
      warning << message->GetLineNumber(env->context()).FromMaybe(-1);
918
1
      warning << " ";
919
3
      v8::String::Utf8Value msg(isolate, message->Get());
920
1
      warning << *msg;
921
1
      USE(ProcessEmitWarningGeneric(env, warning.str().c_str(), "V8"));
922
1
      break;
923
    }
924
1471
    case Isolate::MessageErrorLevel::kMessageError:
925
1471
      TriggerUncaughtException(isolate, error, message);
926
1246
      break;
927
  }
928
1247
}
929
930
820
void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
931
820
  Environment* env = Environment::GetCurrent(args);
932
820
  CHECK(args[0]->IsFunction());
933
1640
  env->set_prepare_stack_trace_callback(args[0].As<Function>());
934
820
}
935
936
6372
static void SetSourceMapsEnabled(const FunctionCallbackInfo<Value>& args) {
937
6372
  Environment* env = Environment::GetCurrent(args);
938
6372
  CHECK(args[0]->IsBoolean());
939
12744
  env->set_source_maps_enabled(args[0].As<Boolean>()->Value());
940
6372
}
941
942
26
static void SetGetSourceMapErrorSource(
943
    const FunctionCallbackInfo<Value>& args) {
944
26
  Environment* env = Environment::GetCurrent(args);
945
26
  CHECK(args[0]->IsFunction());
946
52
  env->set_get_source_map_error_source(args[0].As<Function>());
947
26
}
948
949
6368
static void SetMaybeCacheGeneratedSourceMap(
950
    const FunctionCallbackInfo<Value>& args) {
951
6368
  Environment* env = Environment::GetCurrent(args);
952
6368
  CHECK(args[0]->IsFunction());
953
12736
  env->set_maybe_cache_generated_source_map(args[0].As<Function>());
954
6368
}
955
956
792
static void SetEnhanceStackForFatalException(
957
    const FunctionCallbackInfo<Value>& args) {
958
792
  Environment* env = Environment::GetCurrent(args);
959
792
  CHECK(args[0]->IsFunction());
960
792
  CHECK(args[1]->IsFunction());
961
1584
  env->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
962
1584
  env->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
963
792
}
964
965
// Side effect-free stringification that will never throw exceptions.
966
9
static void NoSideEffectsToString(const FunctionCallbackInfo<Value>& args) {
967
9
  Local<Context> context = args.GetIsolate()->GetCurrentContext();
968
  Local<String> detail_string;
969
18
  if (args[0]->ToDetailString(context).ToLocal(&detail_string))
970
18
    args.GetReturnValue().Set(detail_string);
971
9
}
972
973
87
static void TriggerUncaughtException(const FunctionCallbackInfo<Value>& args) {
974
87
  Isolate* isolate = args.GetIsolate();
975
87
  Environment* env = Environment::GetCurrent(isolate);
976
87
  Local<Value> exception = args[0];
977
87
  Local<Message> message = Exception::CreateMessage(isolate, exception);
978

87
  if (env != nullptr && env->abort_on_uncaught_exception()) {
979
    ReportFatalException(
980
        env, exception, message, EnhanceFatalException::kEnhance);
981
    Abort();
982
  }
983
87
  bool from_promise = args[1]->IsTrue();
984
87
  errors::TriggerUncaughtException(isolate, exception, message, from_promise);
985
13
}
986
987
5618
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
988
5618
  registry->Register(SetPrepareStackTraceCallback);
989
5618
  registry->Register(SetGetSourceMapErrorSource);
990
5618
  registry->Register(SetSourceMapsEnabled);
991
5618
  registry->Register(SetMaybeCacheGeneratedSourceMap);
992
5618
  registry->Register(SetEnhanceStackForFatalException);
993
5618
  registry->Register(NoSideEffectsToString);
994
5618
  registry->Register(TriggerUncaughtException);
995
5618
}
996
997
792
void Initialize(Local<Object> target,
998
                Local<Value> unused,
999
                Local<Context> context,
1000
                void* priv) {
1001
792
  SetMethod(context,
1002
            target,
1003
            "setPrepareStackTraceCallback",
1004
            SetPrepareStackTraceCallback);
1005
792
  SetMethod(context,
1006
            target,
1007
            "setGetSourceMapErrorSource",
1008
            SetGetSourceMapErrorSource);
1009
792
  SetMethod(context, target, "setSourceMapsEnabled", SetSourceMapsEnabled);
1010
792
  SetMethod(context,
1011
            target,
1012
            "setMaybeCacheGeneratedSourceMap",
1013
            SetMaybeCacheGeneratedSourceMap);
1014
792
  SetMethod(context,
1015
            target,
1016
            "setEnhanceStackForFatalException",
1017
            SetEnhanceStackForFatalException);
1018
792
  SetMethodNoSideEffect(
1019
      context, target, "noSideEffectsToString", NoSideEffectsToString);
1020
792
  SetMethod(
1021
      context, target, "triggerUncaughtException", TriggerUncaughtException);
1022
1023
792
  Isolate* isolate = context->GetIsolate();
1024
792
  Local<Object> exit_codes = Object::New(isolate);
1025
1584
  READONLY_PROPERTY(target, "exitCodes", exit_codes);
1026
1027
#define V(Name, Code)                                                          \
1028
  constexpr int k##Name = static_cast<int>(ExitCode::k##Name);                 \
1029
  NODE_DEFINE_CONSTANT(exit_codes, k##Name);
1030
1031
20592
  EXIT_CODE_LIST(V)
1032
#undef V
1033
792
}
1034
1035
309
void DecorateErrorStack(Environment* env,
1036
                        const errors::TryCatchScope& try_catch) {
1037
309
  Local<Value> exception = try_catch.Exception();
1038
1039
315
  if (!exception->IsObject()) return;
1040
1041
300
  Local<Object> err_obj = exception.As<Object>();
1042
1043
300
  if (IsExceptionDecorated(env, err_obj)) return;
1044
1045
297
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
1046
297
  TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
1047
594
  MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
1048
  MaybeLocal<Value> maybe_value =
1049
297
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
1050
1051
  Local<Value> arrow;
1052

891
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
1053
    return;
1054
  }
1055
1056

889
  if (stack.IsEmpty() || !stack.ToLocalChecked()->IsString()) {
1057
3
    return;
1058
  }
1059
1060
  Local<String> decorated_stack = String::Concat(
1061
      env->isolate(),
1062
      String::Concat(env->isolate(),
1063
                     arrow.As<String>(),
1064
                     FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
1065
882
      stack.ToLocalChecked().As<String>());
1066
588
  USE(err_obj->Set(env->context(), env->stack_string(), decorated_stack));
1067
  err_obj->SetPrivate(
1068
588
      env->context(), env->decorated_private_symbol(), True(env->isolate()));
1069
}
1070
1071
1572
void TriggerUncaughtException(Isolate* isolate,
1072
                              Local<Value> error,
1073
                              Local<Message> message,
1074
                              bool from_promise) {
1075
1572
  CHECK(!error.IsEmpty());
1076
1572
  HandleScope scope(isolate);
1077
1078
1572
  if (message.IsEmpty()) message = Exception::CreateMessage(isolate, error);
1079
1080
1572
  CHECK(isolate->InContext());
1081
1572
  Local<Context> context = isolate->GetCurrentContext();
1082
1572
  Environment* env = Environment::GetCurrent(context);
1083
1572
  if (env == nullptr) {
1084
    // This means that the exception happens before Environment is assigned
1085
    // to the context e.g. when there is a SyntaxError in a per-context
1086
    // script - which usually indicates that there is a bug because no JS
1087
    // error is supposed to be thrown at this point.
1088
    // Since we don't have access to Environment here, there is not
1089
    // much we can do, so we just print whatever is useful and crash.
1090
    PrintException(isolate, context, error, message);
1091
    Abort();
1092
  }
1093
1094
  // Invoke process._fatalException() to give user a chance to handle it.
1095
  // We have to grab it from the process object since this has been
1096
  // monkey-patchable.
1097
1572
  Local<Object> process_object = env->process_object();
1098
1572
  Local<String> fatal_exception_string = env->fatal_exception_string();
1099
  Local<Value> fatal_exception_function =
1100
1572
      process_object->Get(env->context(),
1101
3144
                          fatal_exception_string).ToLocalChecked();
1102
  // If the exception happens before process._fatalException is attached
1103
  // during bootstrap, or if the user has patched it incorrectly, exit
1104
  // the current Node.js instance.
1105
1572
  if (!fatal_exception_function->IsFunction()) {
1106
2
    ReportFatalException(
1107
        env, error, message, EnhanceFatalException::kDontEnhance);
1108
2
    env->Exit(ExitCode::kInvalidFatalExceptionMonkeyPatching);
1109
1
    return;
1110
  }
1111
1112
  MaybeLocal<Value> maybe_handled;
1113
1570
  if (env->can_call_into_js()) {
1114
    // We do not expect the global uncaught exception itself to throw any more
1115
    // exceptions. If it does, exit the current Node.js instance.
1116
    errors::TryCatchScope try_catch(env,
1117
1564
                                    errors::TryCatchScope::CatchMode::kFatal);
1118
    // Explicitly disable verbose exception reporting -
1119
    // if process._fatalException() throws an error, we don't want it to
1120
    // trigger the per-isolate message listener which will call this
1121
    // function and recurse.
1122
1564
    try_catch.SetVerbose(false);
1123
    Local<Value> argv[2] = { error,
1124
3128
                             Boolean::New(env->isolate(), from_promise) };
1125
1126
1564
    maybe_handled = fatal_exception_function.As<Function>()->Call(
1127
1564
        env->context(), process_object, arraysize(argv), argv);
1128
  }
1129
1130
  // If process._fatalException() throws, we are now exiting the Node.js
1131
  // instance so return to continue the exit routine.
1132
  // TODO(joyeecheung): return a Maybe here to prevent the caller from
1133
  // stepping on the exit.
1134
  Local<Value> handled;
1135
1556
  if (!maybe_handled.ToLocal(&handled)) {
1136
8
    return;
1137
  }
1138
1139
  // The global uncaught exception handler returns true if the user handles it
1140
  // by e.g. listening to `uncaughtException`. In that case, continue program
1141
  // execution.
1142
  // TODO(joyeecheung): This has been only checking that the return value is
1143
  // exactly false. Investigate whether this can be turned to an "if true"
1144
  // similar to how the worker global uncaught exception handler handles it.
1145
1548
  if (!handled->IsFalse()) {
1146
1258
    return;
1147
  }
1148
1149
  // Now we are certain that the exception is fatal.
1150
290
  ReportFatalException(env, error, message, EnhanceFatalException::kEnhance);
1151
290
  RunAtExit(env);
1152
1153
  // If the global uncaught exception handler sets process.exitCode,
1154
  // exit with that code. Otherwise, exit with `ExitCode::kGenericUserError`.
1155
290
  env->Exit(env->exit_code(ExitCode::kGenericUserError));
1156
}
1157
1158
6
void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {
1159
  // If the try_catch is verbose, the per-isolate message listener is going to
1160
  // handle it (which is going to call into another overload of
1161
  // TriggerUncaughtException()).
1162
6
  if (try_catch.IsVerbose()) {
1163
    return;
1164
  }
1165
1166
  // If the user calls TryCatch::TerminateExecution() on this TryCatch
1167
  // they must call CancelTerminateExecution() again before invoking
1168
  // TriggerUncaughtException() because it will invoke
1169
  // process._fatalException() in the JS land.
1170
6
  CHECK(!try_catch.HasTerminated());
1171
6
  CHECK(try_catch.HasCaught());
1172
9
  HandleScope scope(isolate);
1173
6
  TriggerUncaughtException(isolate,
1174
                           try_catch.Exception(),
1175
                           try_catch.Message(),
1176
                           false /* from_promise */);
1177
}
1178
1179
}  // namespace errors
1180
1181
}  // namespace node
1182
1183
5689
NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)
1184
5618
NODE_MODULE_EXTERNAL_REFERENCE(errors, node::errors::RegisterExternalReferences)