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: 161 267 60.3 %
Date: 2019-02-13 22:28:58 Branches: 149 273 54.6 %

Line Branch Exec Source
1
#include <errno.h>
2
#include <stdarg.h>
3
4
#include "node_errors.h"
5
#include "node_internals.h"
6
#ifdef NODE_REPORT
7
#include "node_report.h"
8
#endif
9
10
namespace node {
11
12
using errors::TryCatchScope;
13
using v8::Context;
14
using v8::Exception;
15
using v8::Function;
16
using v8::FunctionCallbackInfo;
17
using v8::HandleScope;
18
using v8::Int32;
19
using v8::Isolate;
20
using v8::Just;
21
using v8::Local;
22
using v8::Maybe;
23
using v8::MaybeLocal;
24
using v8::Message;
25
using v8::NewStringType;
26
using v8::Number;
27
using v8::Object;
28
using v8::ScriptOrigin;
29
using v8::String;
30
using v8::Undefined;
31
using v8::Value;
32
33
531
bool IsExceptionDecorated(Environment* env, Local<Value> er) {
34

1062
  if (!er.IsEmpty() && er->IsObject()) {
35
525
    Local<Object> err_obj = er.As<Object>();
36
    auto maybe_value =
37
1050
        err_obj->GetPrivate(env->context(), env->decorated_private_symbol());
38
    Local<Value> decorated;
39

1050
    return maybe_value.ToLocal(&decorated) && decorated->IsTrue();
40
  }
41
6
  return false;
42
}
43
44
namespace per_process {
45
4314
static Mutex tty_mutex;
46
}  // namespace per_process
47
48
533
void AppendExceptionLine(Environment* env,
49
                         Local<Value> er,
50
                         Local<Message> message,
51
                         enum ErrorHandlingMode mode) {
52
569
  if (message.IsEmpty()) return;
53
54
533
  HandleScope scope(env->isolate());
55
  Local<Object> err_obj;
56

1066
  if (!er.IsEmpty() && er->IsObject()) {
57
527
    err_obj = er.As<Object>();
58
  }
59
60
  // Print (filename):(line number): (message).
61
533
  ScriptOrigin origin = message->GetScriptOrigin();
62
1030
  node::Utf8Value filename(env->isolate(), message->GetScriptResourceName());
63
533
  const char* filename_string = *filename;
64
1599
  int linenum = message->GetLineNumber(env->context()).FromJust();
65
  // Print line of source code.
66
1066
  MaybeLocal<String> source_line_maybe = message->GetSourceLine(env->context());
67
  node::Utf8Value sourceline(env->isolate(),
68
1030
                             source_line_maybe.ToLocalChecked());
69
533
  const char* sourceline_string = *sourceline;
70
533
  if (strstr(sourceline_string, "node-do-not-add-exception-line") != nullptr)
71
24
    return;
72
73
  // Because of how node modules work, all scripts are wrapped with a
74
  // "function (module, exports, __filename, ...) {"
75
  // to provide script local variables.
76
  //
77
  // When reporting errors on the first line of a script, this wrapper
78
  // function is leaked to the user. There used to be a hack here to
79
  // truncate off the first 62 characters, but it caused numerous other
80
  // problems when vm.runIn*Context() methods were used for non-module
81
  // code.
82
  //
83
  // If we ever decide to re-instate such a hack, the following steps
84
  // must be taken:
85
  //
86
  // 1. Pass a flag around to say "this code was wrapped"
87
  // 2. Update the stack frame output so that it is also correct.
88
  //
89
  // It would probably be simpler to add a line rather than add some
90
  // number of characters to the first line, since V8 truncates the
91
  // sourceline to 78 characters, and we end up not providing very much
92
  // useful debugging info to the user if we remove 62 characters.
93
94
2036
  int script_start = (linenum - origin.ResourceLineOffset()->Value()) == 1
95
749
                         ? origin.ResourceColumnOffset()->Value()
96
749
                         : 0;
97
1527
  int start = message->GetStartColumn(env->context()).FromMaybe(0);
98
1527
  int end = message->GetEndColumn(env->context()).FromMaybe(0);
99
509
  if (start >= script_start) {
100
509
    CHECK_GE(end, start);
101
509
    start -= script_start;
102
509
    end -= script_start;
103
  }
104
105
  char arrow[1024];
106
509
  int max_off = sizeof(arrow) - 2;
107
108
  int off = snprintf(arrow,
109
                     sizeof(arrow),
110
                     "%s:%i\n%s\n",
111
                     filename_string,
112
                     linenum,
113
509
                     sourceline_string);
114
509
  CHECK_GE(off, 0);
115
509
  if (off > max_off) {
116
1
    off = max_off;
117
  }
118
119
  // Print wavy underline (GetUnderline is deprecated).
120
3947
  for (int i = 0; i < start; i++) {
121

3439
    if (sourceline_string[i] == '\0' || off >= max_off) {
122
      break;
123
    }
124
3438
    CHECK_LT(off, max_off);
125
3438
    arrow[off++] = (sourceline_string[i] == '\t') ? '\t' : ' ';
126
  }
127
1406
  for (int i = start; i < end; i++) {
128

919
    if (sourceline_string[i] == '\0' || off >= max_off) {
129
      break;
130
    }
131
897
    CHECK_LT(off, max_off);
132
897
    arrow[off++] = '^';
133
  }
134
509
  CHECK_LE(off, max_off);
135
509
  arrow[off] = '\n';
136
509
  arrow[off + 1] = '\0';
137
138
  Local<String> arrow_str =
139
509
      String::NewFromUtf8(env->isolate(), arrow, NewStringType::kNormal)
140
1018
          .ToLocalChecked();
141
142

1018
  const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
143
  // If allocating arrow_str failed, print it out. There's not much else to do.
144
  // If it's not an error, but something needs to be printed out because
145
  // it's a fatal exception, also print it out from here.
146
  // Otherwise, the arrow property will be attached to the object and handled
147
  // by the caller.
148


633
  if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
149
12
    if (env->printed_error()) return;
150
12
    Mutex::ScopedLock lock(per_process::tty_mutex);
151
12
    env->set_printed_error(true);
152
153
12
    uv_tty_reset_mode();
154
12
    PrintErrorString("\n%s", arrow);
155
12
    return;
156
  }
157
158

1988
  CHECK(err_obj
159
            ->SetPrivate(
160
                env->context(), env->arrow_message_private_symbol(), arrow_str)
161
497
            .FromMaybe(false));
162
}
163
164
[[noreturn]] void Abort() {
165
  DumpBacktrace(stderr);
166
  fflush(stderr);
167
  ABORT_NO_BACKTRACE();
168
}
169
170
[[noreturn]] void Assert(const AssertionInfo& info) {
171
  char name[1024];
172
  GetHumanReadableProcessName(&name);
173
174
  fprintf(stderr,
175
          "%s: %s:%s%s Assertion `%s' failed.\n",
176
          name,
177
          info.file_line,
178
          info.function,
179
          *info.function ? ":" : "",
180
          info.message);
181
  fflush(stderr);
182
183
  Abort();
184
}
185
186
154
void ReportException(Environment* env,
187
                     Local<Value> er,
188
                     Local<Message> message) {
189
154
  CHECK(!er.IsEmpty());
190
154
  HandleScope scope(env->isolate());
191
192
154
  if (message.IsEmpty()) message = Exception::CreateMessage(env->isolate(), er);
193
194
154
  AppendExceptionLine(env, er, message, FATAL_ERROR);
195
196
  Local<Value> trace_value;
197
  Local<Value> arrow;
198
154
  const bool decorated = IsExceptionDecorated(env, er);
199
200

614
  if (er->IsUndefined() || er->IsNull()) {
201
4
    trace_value = Undefined(env->isolate());
202
  } else {
203
456
    Local<Object> err_obj = er->ToObject(env->context()).ToLocalChecked();
204
205
760
    if (!err_obj->Get(env->context(), env->stack_string())
206
456
             .ToLocal(&trace_value)) {
207
2
      trace_value = Undefined(env->isolate());
208
    }
209
    arrow =
210
304
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
211
304
            .ToLocalChecked();
212
  }
213
214
308
  node::Utf8Value trace(env->isolate(), trace_value);
215
216
  // range errors have a trace member set to undefined
217

462
  if (trace.length() > 0 && !trace_value->IsUndefined()) {
218


429
    if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
219
52
      PrintErrorString("%s\n", *trace);
220
    } else {
221
91
      node::Utf8Value arrow_string(env->isolate(), arrow);
222
91
      PrintErrorString("%s\n%s\n", *arrow_string, *trace);
223
    }
224
  } else {
225
    // this really only happens for RangeErrors, since they're the only
226
    // kind that won't have all this info in the trace, or when non-Error
227
    // objects are thrown manually.
228
    MaybeLocal<Value> message;
229
    MaybeLocal<Value> name;
230
231
11
    if (er->IsObject()) {
232
5
      Local<Object> err_obj = er.As<Object>();
233
15
      message = err_obj->Get(env->context(), env->message_string());
234
15
      name = err_obj->Get(env->context(), env->name_string());
235
    }
236
237


49
    if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
238

37
        name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
239
      // Not an error object. Just print as-is.
240
10
      String::Utf8Value message(env->isolate(), er);
241
242
      PrintErrorString("%s\n",
243
10
                       *message ? *message : "<toString() threw exception>");
244
    } else {
245
1
      node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
246
2
      node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());
247
248


3
      if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
249
1
        PrintErrorString("%s: %s\n", *name_string, *message_string);
250
      } else {
251
        node::Utf8Value arrow_string(env->isolate(), arrow);
252
        PrintErrorString(
253
            "%s\n%s: %s\n", *arrow_string, *name_string, *message_string);
254
1
      }
255
    }
256
  }
257
258
154
  fflush(stderr);
259
260
#if HAVE_INSPECTOR
261
308
  env->inspector_agent()->FatalException(er, message);
262
#endif
263
154
}
264
265
3
void ReportException(Environment* env, const v8::TryCatch& try_catch) {
266
3
  ReportException(env, try_catch.Exception(), try_catch.Message());
267
3
}
268
269
403
void PrintErrorString(const char* format, ...) {
270
  va_list ap;
271
403
  va_start(ap, format);
272
#ifdef _WIN32
273
  HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
274
275
  // Check if stderr is something other than a tty/console
276
  if (stderr_handle == INVALID_HANDLE_VALUE || stderr_handle == nullptr ||
277
      uv_guess_handle(_fileno(stderr)) != UV_TTY) {
278
    vfprintf(stderr, format, ap);
279
    va_end(ap);
280
    return;
281
  }
282
283
  // Fill in any placeholders
284
  int n = _vscprintf(format, ap);
285
  std::vector<char> out(n + 1);
286
  vsprintf(out.data(), format, ap);
287
288
  // Get required wide buffer size
289
  n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0);
290
291
  std::vector<wchar_t> wbuf(n);
292
  MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n);
293
294
  // Don't include the null character in the output
295
  CHECK_GT(n, 0);
296
  WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr);
297
#else
298
403
  vfprintf(stderr, format, ap);
299
#endif
300
403
  va_end(ap);
301
403
}
302
303
[[noreturn]] void FatalError(const char* location, const char* message) {
304
  OnFatalError(location, message);
305
  // to suppress compiler warning
306
  ABORT();
307
}
308
309
void OnFatalError(const char* location, const char* message) {
310
  if (location) {
311
    PrintErrorString("FATAL ERROR: %s %s\n", location, message);
312
  } else {
313
    PrintErrorString("FATAL ERROR: %s\n", message);
314
  }
315
#ifdef NODE_REPORT
316
  Isolate* isolate = Isolate::GetCurrent();
317
  HandleScope handle_scope(isolate);
318
  Environment* env = Environment::GetCurrent(isolate);
319
  if (env != nullptr) {
320
    std::shared_ptr<PerIsolateOptions> options = env->isolate_data()->options();
321
    if (options->report_on_fatalerror) {
322
      report::TriggerNodeReport(
323
          isolate, env, message, __func__, "", Local<String>());
324
    }
325
  } else {
326
    report::TriggerNodeReport(
327
        isolate, nullptr, message, __func__, "", Local<String>());
328
  }
329
#endif  // NODE_REPORT
330
  fflush(stderr);
331
  ABORT();
332
}
333
334
namespace errors {
335
336
2011525
TryCatchScope::~TryCatchScope() {
337


1005763
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
338
1
    HandleScope scope(env_->isolate());
339
1
    ReportException(env_, Exception(), Message());
340
1
    env_->Exit(7);
341
  }
342
1005762
}
343
344
4
const char* errno_string(int errorno) {
345
#define ERRNO_CASE(e)                                                          \
346
  case e:                                                                      \
347
    return #e;
348



















4
  switch (errorno) {
349
#ifdef EACCES
350
    ERRNO_CASE(EACCES);
351
#endif
352
353
#ifdef EADDRINUSE
354
    ERRNO_CASE(EADDRINUSE);
355
#endif
356
357
#ifdef EADDRNOTAVAIL
358
    ERRNO_CASE(EADDRNOTAVAIL);
359
#endif
360
361
#ifdef EAFNOSUPPORT
362
    ERRNO_CASE(EAFNOSUPPORT);
363
#endif
364
365
#ifdef EAGAIN
366
    ERRNO_CASE(EAGAIN);
367
#endif
368
369
#ifdef EWOULDBLOCK
370
#if EAGAIN != EWOULDBLOCK
371
    ERRNO_CASE(EWOULDBLOCK);
372
#endif
373
#endif
374
375
#ifdef EALREADY
376
    ERRNO_CASE(EALREADY);
377
#endif
378
379
#ifdef EBADF
380
    ERRNO_CASE(EBADF);
381
#endif
382
383
#ifdef EBADMSG
384
    ERRNO_CASE(EBADMSG);
385
#endif
386
387
#ifdef EBUSY
388
    ERRNO_CASE(EBUSY);
389
#endif
390
391
#ifdef ECANCELED
392
    ERRNO_CASE(ECANCELED);
393
#endif
394
395
#ifdef ECHILD
396
1
    ERRNO_CASE(ECHILD);
397
#endif
398
399
#ifdef ECONNABORTED
400
    ERRNO_CASE(ECONNABORTED);
401
#endif
402
403
#ifdef ECONNREFUSED
404
    ERRNO_CASE(ECONNREFUSED);
405
#endif
406
407
#ifdef ECONNRESET
408
    ERRNO_CASE(ECONNRESET);
409
#endif
410
411
#ifdef EDEADLK
412
    ERRNO_CASE(EDEADLK);
413
#endif
414
415
#ifdef EDESTADDRREQ
416
    ERRNO_CASE(EDESTADDRREQ);
417
#endif
418
419
#ifdef EDOM
420
    ERRNO_CASE(EDOM);
421
#endif
422
423
#ifdef EDQUOT
424
    ERRNO_CASE(EDQUOT);
425
#endif
426
427
#ifdef EEXIST
428
    ERRNO_CASE(EEXIST);
429
#endif
430
431
#ifdef EFAULT
432
    ERRNO_CASE(EFAULT);
433
#endif
434
435
#ifdef EFBIG
436
    ERRNO_CASE(EFBIG);
437
#endif
438
439
#ifdef EHOSTUNREACH
440
    ERRNO_CASE(EHOSTUNREACH);
441
#endif
442
443
#ifdef EIDRM
444
    ERRNO_CASE(EIDRM);
445
#endif
446
447
#ifdef EILSEQ
448
    ERRNO_CASE(EILSEQ);
449
#endif
450
451
#ifdef EINPROGRESS
452
    ERRNO_CASE(EINPROGRESS);
453
#endif
454
455
#ifdef EINTR
456
    ERRNO_CASE(EINTR);
457
#endif
458
459
#ifdef EINVAL
460
    ERRNO_CASE(EINVAL);
461
#endif
462
463
#ifdef EIO
464
    ERRNO_CASE(EIO);
465
#endif
466
467
#ifdef EISCONN
468
    ERRNO_CASE(EISCONN);
469
#endif
470
471
#ifdef EISDIR
472
    ERRNO_CASE(EISDIR);
473
#endif
474
475
#ifdef ELOOP
476
    ERRNO_CASE(ELOOP);
477
#endif
478
479
#ifdef EMFILE
480
    ERRNO_CASE(EMFILE);
481
#endif
482
483
#ifdef EMLINK
484
    ERRNO_CASE(EMLINK);
485
#endif
486
487
#ifdef EMSGSIZE
488
    ERRNO_CASE(EMSGSIZE);
489
#endif
490
491
#ifdef EMULTIHOP
492
    ERRNO_CASE(EMULTIHOP);
493
#endif
494
495
#ifdef ENAMETOOLONG
496
    ERRNO_CASE(ENAMETOOLONG);
497
#endif
498
499
#ifdef ENETDOWN
500
    ERRNO_CASE(ENETDOWN);
501
#endif
502
503
#ifdef ENETRESET
504
    ERRNO_CASE(ENETRESET);
505
#endif
506
507
#ifdef ENETUNREACH
508
    ERRNO_CASE(ENETUNREACH);
509
#endif
510
511
#ifdef ENFILE
512
    ERRNO_CASE(ENFILE);
513
#endif
514
515
#ifdef ENOBUFS
516
    ERRNO_CASE(ENOBUFS);
517
#endif
518
519
#ifdef ENODATA
520
    ERRNO_CASE(ENODATA);
521
#endif
522
523
#ifdef ENODEV
524
    ERRNO_CASE(ENODEV);
525
#endif
526
527
#ifdef ENOENT
528
    ERRNO_CASE(ENOENT);
529
#endif
530
531
#ifdef ENOEXEC
532
    ERRNO_CASE(ENOEXEC);
533
#endif
534
535
#ifdef ENOLINK
536
    ERRNO_CASE(ENOLINK);
537
#endif
538
539
#ifdef ENOLCK
540
#if ENOLINK != ENOLCK
541
    ERRNO_CASE(ENOLCK);
542
#endif
543
#endif
544
545
#ifdef ENOMEM
546
    ERRNO_CASE(ENOMEM);
547
#endif
548
549
#ifdef ENOMSG
550
    ERRNO_CASE(ENOMSG);
551
#endif
552
553
#ifdef ENOPROTOOPT
554
    ERRNO_CASE(ENOPROTOOPT);
555
#endif
556
557
#ifdef ENOSPC
558
    ERRNO_CASE(ENOSPC);
559
#endif
560
561
#ifdef ENOSR
562
    ERRNO_CASE(ENOSR);
563
#endif
564
565
#ifdef ENOSTR
566
    ERRNO_CASE(ENOSTR);
567
#endif
568
569
#ifdef ENOSYS
570
    ERRNO_CASE(ENOSYS);
571
#endif
572
573
#ifdef ENOTCONN
574
    ERRNO_CASE(ENOTCONN);
575
#endif
576
577
#ifdef ENOTDIR
578
    ERRNO_CASE(ENOTDIR);
579
#endif
580
581
#ifdef ENOTEMPTY
582
#if ENOTEMPTY != EEXIST
583
    ERRNO_CASE(ENOTEMPTY);
584
#endif
585
#endif
586
587
#ifdef ENOTSOCK
588
    ERRNO_CASE(ENOTSOCK);
589
#endif
590
591
#ifdef ENOTSUP
592
    ERRNO_CASE(ENOTSUP);
593
#else
594
#ifdef EOPNOTSUPP
595
    ERRNO_CASE(EOPNOTSUPP);
596
#endif
597
#endif
598
599
#ifdef ENOTTY
600
    ERRNO_CASE(ENOTTY);
601
#endif
602
603
#ifdef ENXIO
604
    ERRNO_CASE(ENXIO);
605
#endif
606
607
#ifdef EOVERFLOW
608
    ERRNO_CASE(EOVERFLOW);
609
#endif
610
611
#ifdef EPERM
612
2
    ERRNO_CASE(EPERM);
613
#endif
614
615
#ifdef EPIPE
616
    ERRNO_CASE(EPIPE);
617
#endif
618
619
#ifdef EPROTO
620
    ERRNO_CASE(EPROTO);
621
#endif
622
623
#ifdef EPROTONOSUPPORT
624
    ERRNO_CASE(EPROTONOSUPPORT);
625
#endif
626
627
#ifdef EPROTOTYPE
628
    ERRNO_CASE(EPROTOTYPE);
629
#endif
630
631
#ifdef ERANGE
632
    ERRNO_CASE(ERANGE);
633
#endif
634
635
#ifdef EROFS
636
    ERRNO_CASE(EROFS);
637
#endif
638
639
#ifdef ESPIPE
640
    ERRNO_CASE(ESPIPE);
641
#endif
642
643
#ifdef ESRCH
644
1
    ERRNO_CASE(ESRCH);
645
#endif
646
647
#ifdef ESTALE
648
    ERRNO_CASE(ESTALE);
649
#endif
650
651
#ifdef ETIME
652
    ERRNO_CASE(ETIME);
653
#endif
654
655
#ifdef ETIMEDOUT
656
    ERRNO_CASE(ETIMEDOUT);
657
#endif
658
659
#ifdef ETXTBSY
660
    ERRNO_CASE(ETXTBSY);
661
#endif
662
663
#ifdef EXDEV
664
    ERRNO_CASE(EXDEV);
665
#endif
666
667
    default:
668
      return "";
669
  }
670
}
671
672
}  // namespace errors
673
674
3487
void DecorateErrorStack(Environment* env,
675
                        const errors::TryCatchScope& try_catch) {
676
3487
  Local<Value> exception = try_catch.Exception();
677
678
6601
  if (!exception->IsObject()) return;
679
680
377
  Local<Object> err_obj = exception.As<Object>();
681
682
377
  if (IsExceptionDecorated(env, err_obj)) return;
683
684
374
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
685
374
  TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
686
1122
  MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
687
  MaybeLocal<Value> maybe_value =
688
748
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
689
690
  Local<Value> arrow;
691

1122
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
692
    return;
693
  }
694
695


1870
  if (stack.IsEmpty() || !stack.ToLocalChecked()->IsString()) {
696
1
    return;
697
  }
698
699
  Local<String> decorated_stack = String::Concat(
700
      env->isolate(),
701
      String::Concat(env->isolate(),
702
                     arrow.As<String>(),
703
                     FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
704
1119
      stack.ToLocalChecked().As<String>());
705
1119
  USE(err_obj->Set(env->context(), env->stack_string(), decorated_stack));
706
  err_obj->SetPrivate(
707
1119
      env->context(), env->decorated_private_symbol(), True(env->isolate()));
708
}
709
710
1335
void FatalException(Isolate* isolate,
711
                    Local<Value> error,
712
                    Local<Message> message) {
713
1335
  HandleScope scope(isolate);
714
715
1335
  Environment* env = Environment::GetCurrent(isolate);
716
1335
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
717
1335
  Local<Object> process_object = env->process_object();
718
1335
  Local<String> fatal_exception_string = env->fatal_exception_string();
719
  Local<Value> fatal_exception_function =
720
      process_object->Get(env->context(),
721
4005
                          fatal_exception_string).ToLocalChecked();
722
723
1335
  if (!fatal_exception_function->IsFunction()) {
724
    // Failed before the process._fatalException function was added!
725
    // this is probably pretty bad.  Nothing to do but report and exit.
726
    ReportException(env, error, message);
727
    env->Exit(6);
728
  } else {
729
1335
    errors::TryCatchScope fatal_try_catch(env);
730
731
    // Do not call FatalException when _fatalException handler throws
732
1335
    fatal_try_catch.SetVerbose(false);
733
734
    // This will return true if the JS layer handled it, false otherwise
735
    MaybeLocal<Value> caught = fatal_exception_function.As<Function>()->Call(
736
4005
        env->context(), process_object, 1, &error);
737
738
2513
    if (fatal_try_catch.HasTerminated()) return;
739
740
1333
    if (fatal_try_catch.HasCaught()) {
741
      // The fatal exception function threw, so we must exit
742
3
      ReportException(env, fatal_try_catch);
743
3
      env->Exit(7);
744
745
2660
    } else if (caught.ToLocalChecked()->IsFalse()) {
746
150
      ReportException(env, error, message);
747
748
      // fatal_exception_function call before may have set a new exit code ->
749
      // read it again, otherwise use default for uncaughtException 1
750
150
      Local<String> exit_code = env->exit_code_string();
751
      Local<Value> code;
752


750
      if (!process_object->Get(env->context(), exit_code).ToLocal(&code) ||
753
150
          !code->IsInt32()) {
754
1
        env->Exit(1);
755
      }
756
298
      env->Exit(code.As<Int32>()->Value());
757
1180
    }
758
1180
  }
759
}
760
761
15
void FatalException(const FunctionCallbackInfo<Value>& args) {
762
15
  Isolate* isolate = args.GetIsolate();
763
15
  Environment* env = Environment::GetCurrent(isolate);
764

15
  if (env != nullptr && env->abort_on_uncaught_exception()) {
765
    Abort();
766
  }
767
15
  Local<Value> exception = args[0];
768
15
  Local<Message> message = Exception::CreateMessage(isolate, exception);
769
15
  FatalException(isolate, exception, message);
770
3
}
771
772

12942
}  // namespace node