GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_errors.cc Lines: 292 420 69.5 %
Date: 2021-06-04 04:12:13 Branches: 180 339 53.1 %

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
523
bool IsExceptionDecorated(Environment* env, Local<Value> er) {
38

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

1024
    return maybe_value.ToLocal(&decorated) && decorated->IsTrue();
44
  }
45
11
  return false;
46
}
47
48
namespace per_process {
49
4844
static Mutex tty_mutex;
50
}  // namespace per_process
51
52
935
static std::string GetErrorSource(Isolate* isolate,
53
                                  Local<Context> context,
54
                                  Local<Message> message,
55
                                  bool* added_exception_line) {
56
935
  MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
57
1870
  node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
58
1870
  std::string sourceline(*encoded_source, encoded_source.length());
59
935
  *added_exception_line = false;
60
61
  // If source maps have been enabled, the exception line will instead be
62
  // added in the JavaScript context:
63
935
  Environment* env = Environment::GetCurrent(isolate);
64
  const bool has_source_map_url =
65
2805
      !message->GetScriptOrigin().SourceMapUrl().IsEmpty();
66


935
  if (has_source_map_url && env != nullptr && env->source_maps_enabled()) {
67
13
    return sourceline;
68
  }
69
70
922
  if (sourceline.find("node-do-not-add-exception-line") != std::string::npos) {
71
8
    return sourceline;
72
  }
73
74
  // Because of how node modules work, all scripts are wrapped with a
75
  // "function (module, exports, __filename, ...) {"
76
  // to provide script local variables.
77
  //
78
  // When reporting errors on the first line of a script, this wrapper
79
  // function is leaked to the user. There used to be a hack here to
80
  // truncate off the first 62 characters, but it caused numerous other
81
  // problems when vm.runIn*Context() methods were used for non-module
82
  // code.
83
  //
84
  // If we ever decide to re-instate such a hack, the following steps
85
  // must be taken:
86
  //
87
  // 1. Pass a flag around to say "this code was wrapped"
88
  // 2. Update the stack frame output so that it is also correct.
89
  //
90
  // It would probably be simpler to add a line rather than add some
91
  // number of characters to the first line, since V8 truncates the
92
  // sourceline to 78 characters, and we end up not providing very much
93
  // useful debugging info to the user if we remove 62 characters.
94
95
  // Print (filename):(line number): (message).
96
914
  ScriptOrigin origin = message->GetScriptOrigin();
97
1828
  node::Utf8Value filename(isolate, message->GetScriptResourceName());
98
914
  const char* filename_string = *filename;
99
1828
  int linenum = message->GetLineNumber(context).FromJust();
100
101
1828
  int script_start = (linenum - origin.LineOffset()) == 1
102
1086
                         ? origin.ColumnOffset()
103
914
                         : 0;
104
2742
  int start = message->GetStartColumn(context).FromMaybe(0);
105
2742
  int end = message->GetEndColumn(context).FromMaybe(0);
106
914
  if (start >= script_start) {
107
913
    CHECK_GE(end, start);
108
913
    start -= script_start;
109
913
    end -= script_start;
110
  }
111
112
  std::string buf = SPrintF("%s:%i\n%s\n",
113
                            filename_string,
114
                            linenum,
115
1828
                            sourceline.c_str());
116
914
  CHECK_GT(buf.size(), 0);
117
914
  *added_exception_line = true;
118
119

2742
  if (start > end ||
120

1827
      start < 0 ||
121
913
      static_cast<size_t>(end) > sourceline.size()) {
122
18
    return buf;
123
  }
124
125
896
  constexpr int kUnderlineBufsize = 1020;
126
  char underline_buf[kUnderlineBufsize + 4];
127
896
  int off = 0;
128
  // Print wavy underline (GetUnderline is deprecated).
129
6205
  for (int i = 0; i < start; i++) {
130

5309
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
131
      break;
132
    }
133
5309
    CHECK_LT(off, kUnderlineBufsize);
134
5309
    underline_buf[off++] = (sourceline[i] == '\t') ? '\t' : ' ';
135
  }
136
3543
  for (int i = start; i < end; i++) {
137

2647
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
138
      break;
139
    }
140
2647
    CHECK_LT(off, kUnderlineBufsize);
141
2647
    underline_buf[off++] = '^';
142
  }
143
896
  CHECK_LE(off, kUnderlineBufsize);
144
896
  underline_buf[off++] = '\n';
145
146
896
  return buf + std::string(underline_buf, off);
147
}
148
149
6
void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) {
150
96
  for (int i = 0; i < stack->GetFrameCount(); i++) {
151
84
    Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
152
126
    node::Utf8Value fn_name_s(isolate, stack_frame->GetFunctionName());
153
126
    node::Utf8Value script_name(isolate, stack_frame->GetScriptName());
154
42
    const int line_number = stack_frame->GetLineNumber();
155
42
    const int column = stack_frame->GetColumn();
156
157
42
    if (stack_frame->IsEval()) {
158
      if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
159
        FPrintF(stderr, "    at [eval]:%i:%i\n", line_number, column);
160
      } else {
161
        FPrintF(stderr,
162
                "    at [eval] (%s:%i:%i)\n",
163
                *script_name,
164
                line_number,
165
                column);
166
      }
167
      break;
168
    }
169
170
42
    if (fn_name_s.length() == 0) {
171
11
      FPrintF(stderr, "    at %s:%i:%i\n", script_name, line_number, column);
172
    } else {
173
      FPrintF(stderr,
174
              "    at %s (%s:%i:%i)\n",
175
              fn_name_s,
176
              script_name,
177
              line_number,
178
31
              column);
179
    }
180
  }
181
6
  fflush(stderr);
182
6
}
183
184
396
void PrintException(Isolate* isolate,
185
                    Local<Context> context,
186
                    Local<Value> err,
187
                    Local<Message> message) {
188
  node::Utf8Value reason(isolate,
189
792
                         err->ToDetailString(context)
190
1188
                             .FromMaybe(Local<String>()));
191
396
  bool added_exception_line = false;
192
  std::string source =
193
792
      GetErrorSource(isolate, context, message, &added_exception_line);
194
396
  FPrintF(stderr, "%s\n", source);
195
396
  FPrintF(stderr, "%s\n", reason);
196
197
396
  Local<v8::StackTrace> stack = message->GetStackTrace();
198
396
  if (!stack.IsEmpty()) PrintStackTrace(isolate, stack);
199
396
}
200
201
396
void PrintCaughtException(Isolate* isolate,
202
                          Local<Context> context,
203
                          const v8::TryCatch& try_catch) {
204
396
  CHECK(try_catch.HasCaught());
205
396
  PrintException(isolate, context, try_catch.Exception(), try_catch.Message());
206
396
}
207
208
539
void AppendExceptionLine(Environment* env,
209
                         Local<Value> er,
210
                         Local<Message> message,
211
                         enum ErrorHandlingMode mode) {
212
577
  if (message.IsEmpty()) return;
213
214
1040
  HandleScope scope(env->isolate());
215
  Local<Object> err_obj;
216

1078
  if (!er.IsEmpty() && er->IsObject()) {
217
528
    err_obj = er.As<Object>();
218
  }
219
220
539
  bool added_exception_line = false;
221
  std::string source = GetErrorSource(
222
1040
      env->isolate(), env->context(), message, &added_exception_line);
223
539
  if (!added_exception_line) {
224
21
    return;
225
  }
226
518
  MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
227
228

1036
  const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
229
  // If allocating arrow_str failed, print it out. There's not much else to do.
230
  // If it's not an error, but something needs to be printed out because
231
  // it's a fatal exception, also print it out from here.
232
  // Otherwise, the arrow property will be attached to the object and handled
233
  // by the caller.
234


712
  if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
235
17
    if (env->printed_error()) return;
236
34
    Mutex::ScopedLock lock(per_process::tty_mutex);
237
17
    env->set_printed_error(true);
238
239
17
    ResetStdio();
240
17
    FPrintF(stderr, "\n%s", source);
241
17
    return;
242
  }
243
244

2004
  CHECK(err_obj
245
            ->SetPrivate(env->context(),
246
                         env->arrow_message_private_symbol(),
247
                         arrow_str.ToLocalChecked())
248
            .FromMaybe(false));
249
}
250
251
[[noreturn]] void Abort() {
252
  DumpBacktrace(stderr);
253
  fflush(stderr);
254
  ABORT_NO_BACKTRACE();
255
}
256
257
[[noreturn]] void Assert(const AssertionInfo& info) {
258
  std::string name = GetHumanReadableProcessName();
259
260
  fprintf(stderr,
261
          "%s: %s:%s%s Assertion `%s' failed.\n",
262
          name.c_str(),
263
          info.file_line,
264
          info.function,
265
          *info.function ? ":" : "",
266
          info.message);
267
  fflush(stderr);
268
269
  Abort();
270
}
271
272
enum class EnhanceFatalException { kEnhance, kDontEnhance };
273
274
/**
275
 * Report the exception to the inspector, then print it to stderr.
276
 * This should only be used when the Node.js instance is about to exit
277
 * (i.e. this should be followed by a env->Exit() or an Abort()).
278
 *
279
 * Use enhance_stack = EnhanceFatalException::kDontEnhance
280
 * when it's unsafe to call into JavaScript.
281
 */
282
226
static void ReportFatalException(Environment* env,
283
                                 Local<Value> error,
284
                                 Local<Message> message,
285
                                 EnhanceFatalException enhance_stack) {
286
226
  if (!env->can_call_into_js())
287
    enhance_stack = EnhanceFatalException::kDontEnhance;
288
289
226
  Isolate* isolate = env->isolate();
290
226
  CHECK(!error.IsEmpty());
291
226
  CHECK(!message.IsEmpty());
292
452
  HandleScope scope(isolate);
293
294
226
  AppendExceptionLine(env, error, message, FATAL_ERROR);
295
296
226
  auto report_to_inspector = [&]() {
297
#if HAVE_INSPECTOR
298
226
    env->inspector_agent()->ReportUncaughtException(error, message);
299
#endif
300
452
  };
301
302
  Local<Value> arrow;
303
  Local<Value> stack_trace;
304
226
  bool decorated = IsExceptionDecorated(env, error);
305
306
226
  if (!error->IsObject()) {  // We can only enhance actual errors.
307
11
    report_to_inspector();
308
22
    stack_trace = Undefined(isolate);
309
    // If error is not an object, AppendExceptionLine() has already print the
310
    // source line and the arrow to stderr.
311
    // TODO(joyeecheung): move that side effect out of AppendExceptionLine().
312
    // It is done just to preserve the source line as soon as possible.
313
  } else {
314
215
    Local<Object> err_obj = error.As<Object>();
315
316
426
    auto enhance_with = [&](Local<Function> enhancer) {
317
      Local<Value> enhanced;
318
852
      Local<Value> argv[] = {err_obj};
319

1278
      if (!enhancer.IsEmpty() &&
320
          enhancer
321
1704
              ->Call(env->context(), Undefined(isolate), arraysize(argv), argv)
322
426
              .ToLocal(&enhanced)) {
323
422
        stack_trace = enhanced;
324
      }
325
641
    };
326
327
215
    switch (enhance_stack) {
328
      case EnhanceFatalException::kEnhance: {
329
213
        enhance_with(env->enhance_fatal_stack_before_inspector());
330
213
        report_to_inspector();
331
213
        enhance_with(env->enhance_fatal_stack_after_inspector());
332
213
        break;
333
      }
334
      case EnhanceFatalException::kDontEnhance: {
335
8
        USE(err_obj->Get(env->context(), env->stack_string())
336
2
                .ToLocal(&stack_trace));
337
2
        report_to_inspector();
338
2
        break;
339
      }
340
      default:
341
        UNREACHABLE();
342
    }
343
344
    arrow =
345
645
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
346
215
            .ToLocalChecked();
347
  }
348
349
452
  node::Utf8Value trace(env->isolate(), stack_trace);
350
351
  // range errors have a trace member set to undefined
352

674
  if (trace.length() > 0 && !stack_trace->IsUndefined()) {
353


639
    if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
354
87
      FPrintF(stderr, "%s\n", trace);
355
    } else {
356
252
      node::Utf8Value arrow_string(env->isolate(), arrow);
357
126
      FPrintF(stderr, "%s\n%s\n", arrow_string, trace);
358
    }
359
  } else {
360
    // this really only happens for RangeErrors, since they're the only
361
    // kind that won't have all this info in the trace, or when non-Error
362
    // objects are thrown manually.
363
    MaybeLocal<Value> message;
364
    MaybeLocal<Value> name;
365
366
13
    if (error->IsObject()) {
367
2
      Local<Object> err_obj = error.As<Object>();
368
6
      message = err_obj->Get(env->context(), env->message_string());
369
6
      name = err_obj->Get(env->context(), env->name_string());
370
    }
371
372

45
    if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
373

26
        name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
374
      // Not an error object. Just print as-is.
375
26
      node::Utf8Value message(env->isolate(), error);
376
377
      FPrintF(stderr, "%s\n",
378

13
              *message ? message.ToString() : "<toString() threw exception>");
379
    } else {
380
      node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
381
      node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());
382
383
      if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
384
        FPrintF(stderr, "%s: %s\n", name_string, message_string);
385
      } else {
386
        node::Utf8Value arrow_string(env->isolate(), arrow);
387
        FPrintF(stderr,
388
            "%s\n%s: %s\n", arrow_string, name_string, message_string);
389
      }
390
    }
391
392
13
    if (!env->options()->trace_uncaught) {
393
20
      std::string argv0;
394
10
      if (!env->argv().empty()) argv0 = env->argv()[0];
395
10
      if (argv0.empty()) argv0 = "node";
396
      FPrintF(stderr,
397
              "(Use `%s --trace-uncaught ...` to show where the exception "
398
              "was thrown)\n",
399
10
              fs::Basename(argv0, ".exe"));
400
    }
401
  }
402
403
226
  if (env->options()->trace_uncaught) {
404
3
    Local<StackTrace> trace = message->GetStackTrace();
405
3
    if (!trace.IsEmpty()) {
406
3
      FPrintF(stderr, "Thrown at:\n");
407
3
      PrintStackTrace(env->isolate(), trace);
408
    }
409
  }
410
411
226
  fflush(stderr);
412
226
}
413
414
[[noreturn]] void FatalError(const char* location, const char* message) {
415
  OnFatalError(location, message);
416
  // to suppress compiler warning
417
  ABORT();
418
}
419
420
void OnFatalError(const char* location, const char* message) {
421
  if (location) {
422
    FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message);
423
  } else {
424
    FPrintF(stderr, "FATAL ERROR: %s\n", message);
425
  }
426
427
  Isolate* isolate = Isolate::GetCurrent();
428
  // TODO(legendecas): investigate failures on triggering node-report with
429
  // nullptr isolates.
430
  if (isolate == nullptr) {
431
    fflush(stderr);
432
    ABORT();
433
  }
434
  Environment* env = Environment::GetCurrent(isolate);
435
  bool report_on_fatalerror;
436
  {
437
    Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
438
    report_on_fatalerror = per_process::cli_options->report_on_fatalerror;
439
  }
440
441
  if (report_on_fatalerror) {
442
    report::TriggerNodeReport(
443
        isolate, env, message, "FatalError", "", Local<Object>());
444
  }
445
446
  fflush(stderr);
447
  ABORT();
448
}
449
450
namespace errors {
451
452
1817053
TryCatchScope::~TryCatchScope() {
453


908531
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
454
6
    HandleScope scope(env_->isolate());
455
6
    Local<v8::Value> exception = Exception();
456
6
    Local<v8::Message> message = Message();
457
6
    EnhanceFatalException enhance = CanContinue() ?
458
6
        EnhanceFatalException::kEnhance : EnhanceFatalException::kDontEnhance;
459
6
    if (message.IsEmpty())
460
      message = Exception::CreateMessage(env_->isolate(), exception);
461
6
    ReportFatalException(env_, exception, message, enhance);
462
6
    env_->Exit(7);
463
  }
464
908449
}
465
466
8
const char* errno_string(int errorno) {
467
#define ERRNO_CASE(e)                                                          \
468
  case e:                                                                      \
469
    return #e;
470



















8
  switch (errorno) {
471
#ifdef EACCES
472
    ERRNO_CASE(EACCES);
473
#endif
474
475
#ifdef EADDRINUSE
476
    ERRNO_CASE(EADDRINUSE);
477
#endif
478
479
#ifdef EADDRNOTAVAIL
480
    ERRNO_CASE(EADDRNOTAVAIL);
481
#endif
482
483
#ifdef EAFNOSUPPORT
484
    ERRNO_CASE(EAFNOSUPPORT);
485
#endif
486
487
#ifdef EAGAIN
488
    ERRNO_CASE(EAGAIN);
489
#endif
490
491
#ifdef EWOULDBLOCK
492
#if EAGAIN != EWOULDBLOCK
493
    ERRNO_CASE(EWOULDBLOCK);
494
#endif
495
#endif
496
497
#ifdef EALREADY
498
    ERRNO_CASE(EALREADY);
499
#endif
500
501
#ifdef EBADF
502
    ERRNO_CASE(EBADF);
503
#endif
504
505
#ifdef EBADMSG
506
    ERRNO_CASE(EBADMSG);
507
#endif
508
509
#ifdef EBUSY
510
    ERRNO_CASE(EBUSY);
511
#endif
512
513
#ifdef ECANCELED
514
    ERRNO_CASE(ECANCELED);
515
#endif
516
517
#ifdef ECHILD
518
1
    ERRNO_CASE(ECHILD);
519
#endif
520
521
#ifdef ECONNABORTED
522
    ERRNO_CASE(ECONNABORTED);
523
#endif
524
525
#ifdef ECONNREFUSED
526
    ERRNO_CASE(ECONNREFUSED);
527
#endif
528
529
#ifdef ECONNRESET
530
    ERRNO_CASE(ECONNRESET);
531
#endif
532
533
#ifdef EDEADLK
534
    ERRNO_CASE(EDEADLK);
535
#endif
536
537
#ifdef EDESTADDRREQ
538
    ERRNO_CASE(EDESTADDRREQ);
539
#endif
540
541
#ifdef EDOM
542
    ERRNO_CASE(EDOM);
543
#endif
544
545
#ifdef EDQUOT
546
    ERRNO_CASE(EDQUOT);
547
#endif
548
549
#ifdef EEXIST
550
    ERRNO_CASE(EEXIST);
551
#endif
552
553
#ifdef EFAULT
554
    ERRNO_CASE(EFAULT);
555
#endif
556
557
#ifdef EFBIG
558
    ERRNO_CASE(EFBIG);
559
#endif
560
561
#ifdef EHOSTUNREACH
562
    ERRNO_CASE(EHOSTUNREACH);
563
#endif
564
565
#ifdef EIDRM
566
    ERRNO_CASE(EIDRM);
567
#endif
568
569
#ifdef EILSEQ
570
    ERRNO_CASE(EILSEQ);
571
#endif
572
573
#ifdef EINPROGRESS
574
    ERRNO_CASE(EINPROGRESS);
575
#endif
576
577
#ifdef EINTR
578
    ERRNO_CASE(EINTR);
579
#endif
580
581
#ifdef EINVAL
582
    ERRNO_CASE(EINVAL);
583
#endif
584
585
#ifdef EIO
586
    ERRNO_CASE(EIO);
587
#endif
588
589
#ifdef EISCONN
590
    ERRNO_CASE(EISCONN);
591
#endif
592
593
#ifdef EISDIR
594
    ERRNO_CASE(EISDIR);
595
#endif
596
597
#ifdef ELOOP
598
    ERRNO_CASE(ELOOP);
599
#endif
600
601
#ifdef EMFILE
602
    ERRNO_CASE(EMFILE);
603
#endif
604
605
#ifdef EMLINK
606
    ERRNO_CASE(EMLINK);
607
#endif
608
609
#ifdef EMSGSIZE
610
    ERRNO_CASE(EMSGSIZE);
611
#endif
612
613
#ifdef EMULTIHOP
614
    ERRNO_CASE(EMULTIHOP);
615
#endif
616
617
#ifdef ENAMETOOLONG
618
    ERRNO_CASE(ENAMETOOLONG);
619
#endif
620
621
#ifdef ENETDOWN
622
    ERRNO_CASE(ENETDOWN);
623
#endif
624
625
#ifdef ENETRESET
626
    ERRNO_CASE(ENETRESET);
627
#endif
628
629
#ifdef ENETUNREACH
630
    ERRNO_CASE(ENETUNREACH);
631
#endif
632
633
#ifdef ENFILE
634
    ERRNO_CASE(ENFILE);
635
#endif
636
637
#ifdef ENOBUFS
638
    ERRNO_CASE(ENOBUFS);
639
#endif
640
641
#ifdef ENODATA
642
    ERRNO_CASE(ENODATA);
643
#endif
644
645
#ifdef ENODEV
646
    ERRNO_CASE(ENODEV);
647
#endif
648
649
#ifdef ENOENT
650
    ERRNO_CASE(ENOENT);
651
#endif
652
653
#ifdef ENOEXEC
654
    ERRNO_CASE(ENOEXEC);
655
#endif
656
657
#ifdef ENOLINK
658
    ERRNO_CASE(ENOLINK);
659
#endif
660
661
#ifdef ENOLCK
662
#if ENOLINK != ENOLCK
663
    ERRNO_CASE(ENOLCK);
664
#endif
665
#endif
666
667
#ifdef ENOMEM
668
    ERRNO_CASE(ENOMEM);
669
#endif
670
671
#ifdef ENOMSG
672
    ERRNO_CASE(ENOMSG);
673
#endif
674
675
#ifdef ENOPROTOOPT
676
    ERRNO_CASE(ENOPROTOOPT);
677
#endif
678
679
#ifdef ENOSPC
680
    ERRNO_CASE(ENOSPC);
681
#endif
682
683
#ifdef ENOSR
684
    ERRNO_CASE(ENOSR);
685
#endif
686
687
#ifdef ENOSTR
688
    ERRNO_CASE(ENOSTR);
689
#endif
690
691
#ifdef ENOSYS
692
    ERRNO_CASE(ENOSYS);
693
#endif
694
695
#ifdef ENOTCONN
696
    ERRNO_CASE(ENOTCONN);
697
#endif
698
699
#ifdef ENOTDIR
700
    ERRNO_CASE(ENOTDIR);
701
#endif
702
703
#ifdef ENOTEMPTY
704
#if ENOTEMPTY != EEXIST
705
    ERRNO_CASE(ENOTEMPTY);
706
#endif
707
#endif
708
709
#ifdef ENOTSOCK
710
    ERRNO_CASE(ENOTSOCK);
711
#endif
712
713
#ifdef ENOTSUP
714
    ERRNO_CASE(ENOTSUP);
715
#else
716
#ifdef EOPNOTSUPP
717
    ERRNO_CASE(EOPNOTSUPP);
718
#endif
719
#endif
720
721
#ifdef ENOTTY
722
    ERRNO_CASE(ENOTTY);
723
#endif
724
725
#ifdef ENXIO
726
    ERRNO_CASE(ENXIO);
727
#endif
728
729
#ifdef EOVERFLOW
730
    ERRNO_CASE(EOVERFLOW);
731
#endif
732
733
#ifdef EPERM
734
6
    ERRNO_CASE(EPERM);
735
#endif
736
737
#ifdef EPIPE
738
    ERRNO_CASE(EPIPE);
739
#endif
740
741
#ifdef EPROTO
742
    ERRNO_CASE(EPROTO);
743
#endif
744
745
#ifdef EPROTONOSUPPORT
746
    ERRNO_CASE(EPROTONOSUPPORT);
747
#endif
748
749
#ifdef EPROTOTYPE
750
    ERRNO_CASE(EPROTOTYPE);
751
#endif
752
753
#ifdef ERANGE
754
    ERRNO_CASE(ERANGE);
755
#endif
756
757
#ifdef EROFS
758
    ERRNO_CASE(EROFS);
759
#endif
760
761
#ifdef ESPIPE
762
    ERRNO_CASE(ESPIPE);
763
#endif
764
765
#ifdef ESRCH
766
1
    ERRNO_CASE(ESRCH);
767
#endif
768
769
#ifdef ESTALE
770
    ERRNO_CASE(ESTALE);
771
#endif
772
773
#ifdef ETIME
774
    ERRNO_CASE(ETIME);
775
#endif
776
777
#ifdef ETIMEDOUT
778
    ERRNO_CASE(ETIMEDOUT);
779
#endif
780
781
#ifdef ETXTBSY
782
    ERRNO_CASE(ETXTBSY);
783
#endif
784
785
#ifdef EXDEV
786
    ERRNO_CASE(EXDEV);
787
#endif
788
789
    default:
790
      return "";
791
  }
792
}
793
794
1413
void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
795
1413
  Isolate* isolate = message->GetIsolate();
796
1413
  switch (message->ErrorLevel()) {
797
    case Isolate::MessageErrorLevel::kMessageWarning: {
798
1
      Environment* env = Environment::GetCurrent(isolate);
799
1
      if (!env) {
800
        break;
801
      }
802
3
      Utf8Value filename(isolate, message->GetScriptOrigin().ResourceName());
803
      // (filename):(line) (message)
804
2
      std::stringstream warning;
805
1
      warning << *filename;
806
1
      warning << ":";
807
3
      warning << message->GetLineNumber(env->context()).FromMaybe(-1);
808
1
      warning << " ";
809
3
      v8::String::Utf8Value msg(isolate, message->Get());
810
1
      warning << *msg;
811
1
      USE(ProcessEmitWarningGeneric(env, warning.str().c_str(), "V8"));
812
1
      break;
813
    }
814
    case Isolate::MessageErrorLevel::kMessageError:
815
1412
      TriggerUncaughtException(isolate, error, message);
816
1224
      break;
817
  }
818
1225
}
819
820
486
void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
821
486
  Environment* env = Environment::GetCurrent(args);
822
972
  CHECK(args[0]->IsFunction());
823
972
  env->set_prepare_stack_trace_callback(args[0].As<Function>());
824
486
}
825
826
16
static void EnableSourceMaps(const FunctionCallbackInfo<Value>& args) {
827
16
  Environment* env = Environment::GetCurrent(args);
828
16
  env->set_source_maps_enabled(true);
829
16
}
830
831
470
static void SetEnhanceStackForFatalException(
832
    const FunctionCallbackInfo<Value>& args) {
833
470
  Environment* env = Environment::GetCurrent(args);
834
940
  CHECK(args[0]->IsFunction());
835
940
  CHECK(args[1]->IsFunction());
836
940
  env->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
837
940
  env->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
838
470
}
839
840
// Side effect-free stringification that will never throw exceptions.
841
9
static void NoSideEffectsToString(const FunctionCallbackInfo<Value>& args) {
842
9
  Local<Context> context = args.GetIsolate()->GetCurrentContext();
843
  Local<String> detail_string;
844
27
  if (args[0]->ToDetailString(context).ToLocal(&detail_string))
845
18
    args.GetReturnValue().Set(detail_string);
846
9
}
847
848
46
static void TriggerUncaughtException(const FunctionCallbackInfo<Value>& args) {
849
46
  Isolate* isolate = args.GetIsolate();
850
46
  Environment* env = Environment::GetCurrent(isolate);
851
46
  Local<Value> exception = args[0];
852
46
  Local<Message> message = Exception::CreateMessage(isolate, exception);
853

46
  if (env != nullptr && env->abort_on_uncaught_exception()) {
854
    ReportFatalException(
855
        env, exception, message, EnhanceFatalException::kEnhance);
856
    Abort();
857
  }
858
92
  bool from_promise = args[1]->IsTrue();
859
46
  errors::TriggerUncaughtException(isolate, exception, message, from_promise);
860
11
}
861
862
4778
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
863
4778
  registry->Register(SetPrepareStackTraceCallback);
864
4778
  registry->Register(EnableSourceMaps);
865
4778
  registry->Register(SetEnhanceStackForFatalException);
866
4778
  registry->Register(NoSideEffectsToString);
867
4778
  registry->Register(TriggerUncaughtException);
868
4778
}
869
870
469
void Initialize(Local<Object> target,
871
                Local<Value> unused,
872
                Local<Context> context,
873
                void* priv) {
874
469
  Environment* env = Environment::GetCurrent(context);
875
  env->SetMethod(
876
470
      target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
877
470
  env->SetMethod(target, "enableSourceMaps", EnableSourceMaps);
878
  env->SetMethod(target,
879
                 "setEnhanceStackForFatalException",
880
469
                 SetEnhanceStackForFatalException);
881
  env->SetMethodNoSideEffect(
882
469
      target, "noSideEffectsToString", NoSideEffectsToString);
883
470
  env->SetMethod(target, "triggerUncaughtException", TriggerUncaughtException);
884
470
}
885
886
304
void DecorateErrorStack(Environment* env,
887
                        const errors::TryCatchScope& try_catch) {
888
304
  Local<Value> exception = try_catch.Exception();
889
890
316
  if (!exception->IsObject()) return;
891
892
297
  Local<Object> err_obj = exception.As<Object>();
893
894
297
  if (IsExceptionDecorated(env, err_obj)) return;
895
896
294
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
897
586
  TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
898
882
  MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
899
  MaybeLocal<Value> maybe_value =
900
588
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
901
902
  Local<Value> arrow;
903

882
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
904
    return;
905
  }
906
907

1176
  if (stack.IsEmpty() || !stack.ToLocalChecked()->IsString()) {
908
2
    return;
909
  }
910
911
  Local<String> decorated_stack = String::Concat(
912
      env->isolate(),
913
      String::Concat(env->isolate(),
914
                     arrow.As<String>(),
915
                     FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
916
876
      stack.ToLocalChecked().As<String>());
917
876
  USE(err_obj->Set(env->context(), env->stack_string(), decorated_stack));
918
  err_obj->SetPrivate(
919
876
      env->context(), env->decorated_private_symbol(), True(env->isolate()));
920
}
921
922
1467
void TriggerUncaughtException(Isolate* isolate,
923
                              Local<Value> error,
924
                              Local<Message> message,
925
                              bool from_promise) {
926
1467
  CHECK(!error.IsEmpty());
927
1468
  HandleScope scope(isolate);
928
929
1467
  if (message.IsEmpty()) message = Exception::CreateMessage(isolate, error);
930
931
1467
  CHECK(isolate->InContext());
932
1467
  Local<Context> context = isolate->GetCurrentContext();
933
1467
  Environment* env = Environment::GetCurrent(context);
934
1467
  if (env == nullptr) {
935
    // This means that the exception happens before Environment is assigned
936
    // to the context e.g. when there is a SyntaxError in a per-context
937
    // script - which usually indicates that there is a bug because no JS
938
    // error is supposed to be thrown at this point.
939
    // Since we don't have access to Environment here, there is not
940
    // much we can do, so we just print whatever is useful and crash.
941
    PrintException(isolate, context, error, message);
942
    Abort();
943
  }
944
945
  // Invoke process._fatalException() to give user a chance to handle it.
946
  // We have to grab it from the process object since this has been
947
  // monkey-patchable.
948
1467
  Local<Object> process_object = env->process_object();
949
1467
  Local<String> fatal_exception_string = env->fatal_exception_string();
950
  Local<Value> fatal_exception_function =
951
2934
      process_object->Get(env->context(),
952
5868
                          fatal_exception_string).ToLocalChecked();
953
  // If the exception happens before process._fatalException is attached
954
  // during bootstrap, or if the user has patched it incorrectly, exit
955
  // the current Node.js instance.
956
1467
  if (!fatal_exception_function->IsFunction()) {
957
    ReportFatalException(
958
2
        env, error, message, EnhanceFatalException::kDontEnhance);
959
2
    env->Exit(6);
960
1
    return;
961
  }
962
963
  MaybeLocal<Value> maybe_handled;
964
1465
  if (env->can_call_into_js()) {
965
    // We do not expect the global uncaught exception itself to throw any more
966
    // exceptions. If it does, exit the current Node.js instance.
967
    errors::TryCatchScope try_catch(env,
968
2915
                                    errors::TryCatchScope::CatchMode::kFatal);
969
    // Explicitly disable verbose exception reporting -
970
    // if process._fatalException() throws an error, we don't want it to
971
    // trigger the per-isolate message listener which will call this
972
    // function and recurse.
973
1459
    try_catch.SetVerbose(false);
974
    Local<Value> argv[2] = { error,
975
2918
                             Boolean::New(env->isolate(), from_promise) };
976
977
2915
    maybe_handled = fatal_exception_function.As<Function>()->Call(
978
5833
        env->context(), process_object, arraysize(argv), argv);
979
  }
980
981
  // If process._fatalException() throws, we are now exiting the Node.js
982
  // instance so return to continue the exit routine.
983
  // TODO(joyeecheung): return a Maybe here to prevent the caller from
984
  // stepping on the exit.
985
  Local<Value> handled;
986
1456
  if (!maybe_handled.ToLocal(&handled)) {
987
7
    return;
988
  }
989
990
  // The global uncaught exception handler returns true if the user handles it
991
  // by e.g. listening to `uncaughtException`. In that case, continue program
992
  // execution.
993
  // TODO(joyeecheung): This has been only checking that the return value is
994
  // exactly false. Investigate whether this can be turned to an "if true"
995
  // similar to how the worker global uncaught exception handler handles it.
996
1449
  if (!handled->IsFalse()) {
997
1231
    return;
998
  }
999
1000
  // Now we are certain that the exception is fatal.
1001
218
  ReportFatalException(env, error, message, EnhanceFatalException::kEnhance);
1002
218
  RunAtExit(env);
1003
1004
  // If the global uncaught exception handler sets process.exitCode,
1005
  // exit with that code. Otherwise, exit with 1.
1006
218
  Local<String> exit_code = env->exit_code_string();
1007
  Local<Value> code;
1008

872
  if (process_object->Get(env->context(), exit_code).ToLocal(&code) &&
1009
218
      code->IsInt32()) {
1010
434
    env->Exit(code.As<Int32>()->Value());
1011
  } else {
1012
1
    env->Exit(1);
1013
  }
1014
}
1015
1016
6
void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {
1017
  // If the try_catch is verbose, the per-isolate message listener is going to
1018
  // handle it (which is going to call into another overload of
1019
  // TriggerUncaughtException()).
1020
6
  if (try_catch.IsVerbose()) {
1021
    return;
1022
  }
1023
1024
  // If the user calls TryCatch::TerminateExecution() on this TryCatch
1025
  // they must call CancelTerminateExecution() again before invoking
1026
  // TriggerUncaughtException() because it will invoke
1027
  // process._fatalException() in the JS land.
1028
6
  CHECK(!try_catch.HasTerminated());
1029
6
  CHECK(try_catch.HasCaught());
1030
9
  HandleScope scope(isolate);
1031
6
  TriggerUncaughtException(isolate,
1032
                           try_catch.Exception(),
1033
                           try_catch.Message(),
1034
6
                           false /* from_promise */);
1035
}
1036
1037
}  // namespace errors
1038
1039
}  // namespace node
1040
1041
4836
NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)
1042

19310
NODE_MODULE_EXTERNAL_REFERENCE(errors, node::errors::RegisterExternalReferences)