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: 275 406 67.7 %
Date: 2020-05-27 22:15:15 Branches: 169 327 51.7 %

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_internals.h"
7
#include "node_report.h"
8
#include "node_process.h"
9
#include "node_v8_platform-inl.h"
10
#include "util-inl.h"
11
12
namespace node {
13
14
using errors::TryCatchScope;
15
using v8::Boolean;
16
using v8::Context;
17
using v8::Exception;
18
using v8::Function;
19
using v8::FunctionCallbackInfo;
20
using v8::HandleScope;
21
using v8::Int32;
22
using v8::Isolate;
23
using v8::Just;
24
using v8::Local;
25
using v8::Maybe;
26
using v8::MaybeLocal;
27
using v8::Message;
28
using v8::Number;
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
487
bool IsExceptionDecorated(Environment* env, Local<Value> er) {
38

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

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

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

4309
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
125
      break;
126
    }
127
4309
    CHECK_LT(off, kUnderlineBufsize);
128
4309
    underline_buf[off++] = (sourceline[i] == '\t') ? '\t' : ' ';
129
  }
130
3534
  for (int i = start; i < end; i++) {
131

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

1000
  if (!er.IsEmpty() && er->IsObject()) {
212
492
    err_obj = er.As<Object>();
213
  }
214
215
500
  bool added_exception_line = false;
216
  std::string source = GetErrorSource(
217
968
      env->isolate(), env->context(), message, &added_exception_line);
218
500
  if (!added_exception_line) {
219
18
    return;
220
  }
221
482
  MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
222
223

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


665
  if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
230
14
    if (env->printed_error()) return;
231
28
    Mutex::ScopedLock lock(per_process::tty_mutex);
232
14
    env->set_printed_error(true);
233
234
14
    ResetStdio();
235
14
    FPrintF(stderr, "\n%s", source);
236
14
    return;
237
  }
238
239

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

1206
      if (!enhancer.IsEmpty() &&
315
          enhancer
316
1608
              ->Call(env->context(), Undefined(isolate), arraysize(argv), argv)
317
402
              .ToLocal(&enhanced)) {
318
398
        stack_trace = enhanced;
319
      }
320
603
    };
321
322
201
    switch (enhance_stack) {
323
      case EnhanceFatalException::kEnhance: {
324
201
        enhance_with(env->enhance_fatal_stack_before_inspector());
325
201
        report_to_inspector();
326
201
        enhance_with(env->enhance_fatal_stack_after_inspector());
327
201
        break;
328
      }
329
      case EnhanceFatalException::kDontEnhance: {
330
        USE(err_obj->Get(env->context(), env->stack_string())
331
                .ToLocal(&stack_trace));
332
        report_to_inspector();
333
        break;
334
      }
335
      default:
336
        UNREACHABLE();
337
    }
338
339
    arrow =
340
603
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
341
201
            .ToLocalChecked();
342
  }
343
344
418
  node::Utf8Value trace(env->isolate(), stack_trace);
345
346
  // range errors have a trace member set to undefined
347

623
  if (trace.length() > 0 && !stack_trace->IsUndefined()) {
348


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

36
    if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
368

20
        name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
369
      // Not an error object. Just print as-is.
370
20
      node::Utf8Value message(env->isolate(), error);
371
372
      FPrintF(stderr, "%s\n",
373

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


1118966
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
443
5
    HandleScope scope(env_->isolate());
444
5
    Local<v8::Value> exception = Exception();
445
5
    Local<v8::Message> message = Message();
446
5
    EnhanceFatalException enhance = CanContinue() ?
447
5
        EnhanceFatalException::kEnhance : EnhanceFatalException::kDontEnhance;
448
5
    if (message.IsEmpty())
449
      message = Exception::CreateMessage(env_->isolate(), exception);
450
5
    ReportFatalException(env_, exception, message, enhance);
451
5
    env_->Exit(7);
452
  }
453
1118960
}
454
455
4
const char* errno_string(int errorno) {
456
#define ERRNO_CASE(e)                                                          \
457
  case e:                                                                      \
458
    return #e;
459



















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

24
  if (env != nullptr && env->abort_on_uncaught_exception()) {
843
    ReportFatalException(
844
        env, exception, message, EnhanceFatalException::kEnhance);
845
    Abort();
846
  }
847
48
  bool from_promise = args[1]->IsTrue();
848
24
  errors::TriggerUncaughtException(isolate, exception, message, from_promise);
849
5
}
850
851
4594
void Initialize(Local<Object> target,
852
                Local<Value> unused,
853
                Local<Context> context,
854
                void* priv) {
855
4594
  Environment* env = Environment::GetCurrent(context);
856
  env->SetMethod(
857
4594
      target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
858
4594
  env->SetMethod(target, "enableSourceMaps", EnableSourceMaps);
859
  env->SetMethod(target,
860
                 "setEnhanceStackForFatalException",
861
4594
                 SetEnhanceStackForFatalException);
862
  env->SetMethodNoSideEffect(
863
4594
      target, "noSideEffectsToString", NoSideEffectsToString);
864
4594
  env->SetMethod(target, "triggerUncaughtException", TriggerUncaughtException);
865
4594
}
866
867
286
void DecorateErrorStack(Environment* env,
868
                        const errors::TryCatchScope& try_catch) {
869
286
  Local<Value> exception = try_catch.Exception();
870
871
299
  if (!exception->IsObject()) return;
872
873
278
  Local<Object> err_obj = exception.As<Object>();
874
875
278
  if (IsExceptionDecorated(env, err_obj)) return;
876
877
275
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
878
548
  TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
879
825
  MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
880
  MaybeLocal<Value> maybe_value =
881
550
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
882
883
  Local<Value> arrow;
884

825
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
885
    return;
886
  }
887
888

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

816
  if (process_object->Get(env->context(), exit_code).ToLocal(&code) &&
989
204
      code->IsInt32()) {
990
406
    env->Exit(code.As<Int32>()->Value());
991
  } else {
992
1
    env->Exit(1);
993
  }
994
}
995
996
4
void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {
997
  // If the try_catch is verbose, the per-isolate message listener is going to
998
  // handle it (which is going to call into another overload of
999
  // TriggerUncaughtException()).
1000
4
  if (try_catch.IsVerbose()) {
1001
    return;
1002
  }
1003
1004
  // If the user calls TryCatch::TerminateExecution() on this TryCatch
1005
  // they must call CancelTerminateExecution() again before invoking
1006
  // TriggerUncaughtException() because it will invoke
1007
  // process._fatalException() in the JS land.
1008
4
  CHECK(!try_catch.HasTerminated());
1009
4
  CHECK(try_catch.HasCaught());
1010
7
  HandleScope scope(isolate);
1011
4
  TriggerUncaughtException(isolate,
1012
                           try_catch.Exception(),
1013
                           try_catch.Message(),
1014
4
                           false /* from_promise */);
1015
}
1016
1017
}  // namespace errors
1018
1019
}  // namespace node
1020
1021

17303
NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)