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: 98 265 37.0 %
Date: 2019-02-01 22:03:38 Branches: 70 263 26.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 v8::Context;
13
using v8::Exception;
14
using v8::Function;
15
using v8::FunctionCallbackInfo;
16
using v8::HandleScope;
17
using v8::Int32;
18
using v8::Isolate;
19
using v8::Just;
20
using v8::Local;
21
using v8::Maybe;
22
using v8::MaybeLocal;
23
using v8::Message;
24
using v8::NewStringType;
25
using v8::Number;
26
using v8::Object;
27
using v8::ScriptOrigin;
28
using v8::String;
29
using v8::Undefined;
30
using v8::Value;
31
32
1
bool IsExceptionDecorated(Environment* env, Local<Value> er) {
33

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

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

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

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

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

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


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

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

4
  if (er->IsUndefined() || er->IsNull()) {
206
    trace_value = Undefined(env->isolate());
207
  } else {
208
3
    Local<Object> err_obj = er->ToObject(env->context()).ToLocalChecked();
209
210
    trace_value = err_obj->Get(env->context(),
211
4
                               env->stack_string()).ToLocalChecked();
212
    arrow =
213
2
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
214
2
            .ToLocalChecked();
215
  }
216
217
2
  node::Utf8Value trace(env->isolate(), trace_value);
218
219
  // range errors have a trace member set to undefined
220

3
  if (trace.length() > 0 && !trace_value->IsUndefined()) {
221


3
    if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
222
      PrintErrorString("%s\n", *trace);
223
    } else {
224
1
      node::Utf8Value arrow_string(env->isolate(), arrow);
225
1
      PrintErrorString("%s\n%s\n", *arrow_string, *trace);
226
    }
227
  } else {
228
    // this really only happens for RangeErrors, since they're the only
229
    // kind that won't have all this info in the trace, or when non-Error
230
    // objects are thrown manually.
231
    Local<Value> message;
232
    Local<Value> name;
233
234
    if (er->IsObject()) {
235
      Local<Object> err_obj = er.As<Object>();
236
      message = err_obj->Get(env->context(),
237
                             env->message_string()).ToLocalChecked();
238
      name = err_obj->Get(env->context(),
239
          FIXED_ONE_BYTE_STRING(env->isolate(), "name")).ToLocalChecked();
240
    }
241
242
    if (message.IsEmpty() || message->IsUndefined() || name.IsEmpty() ||
243
        name->IsUndefined()) {
244
      // Not an error object. Just print as-is.
245
      String::Utf8Value message(env->isolate(), er);
246
247
      PrintErrorString("%s\n",
248
                       *message ? *message : "<toString() threw exception>");
249
    } else {
250
      node::Utf8Value name_string(env->isolate(), name);
251
      node::Utf8Value message_string(env->isolate(), message);
252
253
      if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
254
        PrintErrorString("%s: %s\n", *name_string, *message_string);
255
      } else {
256
        node::Utf8Value arrow_string(env->isolate(), arrow);
257
        PrintErrorString(
258
            "%s\n%s: %s\n", *arrow_string, *name_string, *message_string);
259
      }
260
    }
261
  }
262
263
1
  fflush(stderr);
264
265
#if HAVE_INSPECTOR
266
2
  env->inspector_agent()->FatalException(er, message);
267
#endif
268
1
}
269
270
void ReportException(Environment* env, const v8::TryCatch& try_catch) {
271
  ReportException(env, try_catch.Exception(), try_catch.Message());
272
}
273
274
1
void PrintErrorString(const char* format, ...) {
275
  va_list ap;
276
1
  va_start(ap, format);
277
#ifdef _WIN32
278
  HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
279
280
  // Check if stderr is something other than a tty/console
281
  if (stderr_handle == INVALID_HANDLE_VALUE || stderr_handle == nullptr ||
282
      uv_guess_handle(_fileno(stderr)) != UV_TTY) {
283
    vfprintf(stderr, format, ap);
284
    va_end(ap);
285
    return;
286
  }
287
288
  // Fill in any placeholders
289
  int n = _vscprintf(format, ap);
290
  std::vector<char> out(n + 1);
291
  vsprintf(out.data(), format, ap);
292
293
  // Get required wide buffer size
294
  n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0);
295
296
  std::vector<wchar_t> wbuf(n);
297
  MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n);
298
299
  // Don't include the null character in the output
300
  CHECK_GT(n, 0);
301
  WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr);
302
#else
303
1
  vfprintf(stderr, format, ap);
304
#endif
305
1
  va_end(ap);
306
1
}
307
308
[[noreturn]] void FatalError(const char* location, const char* message) {
309
  OnFatalError(location, message);
310
  // to suppress compiler warning
311
  ABORT();
312
}
313
314
void OnFatalError(const char* location, const char* message) {
315
  if (location) {
316
    PrintErrorString("FATAL ERROR: %s %s\n", location, message);
317
  } else {
318
    PrintErrorString("FATAL ERROR: %s\n", message);
319
  }
320
#ifdef NODE_REPORT
321
  Isolate* isolate = Isolate::GetCurrent();
322
  HandleScope handle_scope(isolate);
323
  Environment* env = Environment::GetCurrent(isolate);
324
  if (env != nullptr) {
325
    std::shared_ptr<PerIsolateOptions> options = env->isolate_data()->options();
326
    if (options->report_on_fatalerror) {
327
      report::TriggerNodeReport(
328
          isolate, env, message, __func__, "", Local<String>());
329
    }
330
  } else {
331
    report::TriggerNodeReport(
332
        isolate, nullptr, message, __func__, "", Local<String>());
333
  }
334
#endif  // NODE_REPORT
335
  fflush(stderr);
336
  ABORT();
337
}
338
339
namespace errors {
340
341
40768
TryCatchScope::~TryCatchScope() {
342


20384
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
343
    HandleScope scope(env_->isolate());
344
    ReportException(env_, Exception(), Message());
345
    env_->Exit(7);
346
  }
347
20384
}
348
349
const char* errno_string(int errorno) {
350
#define ERRNO_CASE(e)                                                          \
351
  case e:                                                                      \
352
    return #e;
353
  switch (errorno) {
354
#ifdef EACCES
355
    ERRNO_CASE(EACCES);
356
#endif
357
358
#ifdef EADDRINUSE
359
    ERRNO_CASE(EADDRINUSE);
360
#endif
361
362
#ifdef EADDRNOTAVAIL
363
    ERRNO_CASE(EADDRNOTAVAIL);
364
#endif
365
366
#ifdef EAFNOSUPPORT
367
    ERRNO_CASE(EAFNOSUPPORT);
368
#endif
369
370
#ifdef EAGAIN
371
    ERRNO_CASE(EAGAIN);
372
#endif
373
374
#ifdef EWOULDBLOCK
375
#if EAGAIN != EWOULDBLOCK
376
    ERRNO_CASE(EWOULDBLOCK);
377
#endif
378
#endif
379
380
#ifdef EALREADY
381
    ERRNO_CASE(EALREADY);
382
#endif
383
384
#ifdef EBADF
385
    ERRNO_CASE(EBADF);
386
#endif
387
388
#ifdef EBADMSG
389
    ERRNO_CASE(EBADMSG);
390
#endif
391
392
#ifdef EBUSY
393
    ERRNO_CASE(EBUSY);
394
#endif
395
396
#ifdef ECANCELED
397
    ERRNO_CASE(ECANCELED);
398
#endif
399
400
#ifdef ECHILD
401
    ERRNO_CASE(ECHILD);
402
#endif
403
404
#ifdef ECONNABORTED
405
    ERRNO_CASE(ECONNABORTED);
406
#endif
407
408
#ifdef ECONNREFUSED
409
    ERRNO_CASE(ECONNREFUSED);
410
#endif
411
412
#ifdef ECONNRESET
413
    ERRNO_CASE(ECONNRESET);
414
#endif
415
416
#ifdef EDEADLK
417
    ERRNO_CASE(EDEADLK);
418
#endif
419
420
#ifdef EDESTADDRREQ
421
    ERRNO_CASE(EDESTADDRREQ);
422
#endif
423
424
#ifdef EDOM
425
    ERRNO_CASE(EDOM);
426
#endif
427
428
#ifdef EDQUOT
429
    ERRNO_CASE(EDQUOT);
430
#endif
431
432
#ifdef EEXIST
433
    ERRNO_CASE(EEXIST);
434
#endif
435
436
#ifdef EFAULT
437
    ERRNO_CASE(EFAULT);
438
#endif
439
440
#ifdef EFBIG
441
    ERRNO_CASE(EFBIG);
442
#endif
443
444
#ifdef EHOSTUNREACH
445
    ERRNO_CASE(EHOSTUNREACH);
446
#endif
447
448
#ifdef EIDRM
449
    ERRNO_CASE(EIDRM);
450
#endif
451
452
#ifdef EILSEQ
453
    ERRNO_CASE(EILSEQ);
454
#endif
455
456
#ifdef EINPROGRESS
457
    ERRNO_CASE(EINPROGRESS);
458
#endif
459
460
#ifdef EINTR
461
    ERRNO_CASE(EINTR);
462
#endif
463
464
#ifdef EINVAL
465
    ERRNO_CASE(EINVAL);
466
#endif
467
468
#ifdef EIO
469
    ERRNO_CASE(EIO);
470
#endif
471
472
#ifdef EISCONN
473
    ERRNO_CASE(EISCONN);
474
#endif
475
476
#ifdef EISDIR
477
    ERRNO_CASE(EISDIR);
478
#endif
479
480
#ifdef ELOOP
481
    ERRNO_CASE(ELOOP);
482
#endif
483
484
#ifdef EMFILE
485
    ERRNO_CASE(EMFILE);
486
#endif
487
488
#ifdef EMLINK
489
    ERRNO_CASE(EMLINK);
490
#endif
491
492
#ifdef EMSGSIZE
493
    ERRNO_CASE(EMSGSIZE);
494
#endif
495
496
#ifdef EMULTIHOP
497
    ERRNO_CASE(EMULTIHOP);
498
#endif
499
500
#ifdef ENAMETOOLONG
501
    ERRNO_CASE(ENAMETOOLONG);
502
#endif
503
504
#ifdef ENETDOWN
505
    ERRNO_CASE(ENETDOWN);
506
#endif
507
508
#ifdef ENETRESET
509
    ERRNO_CASE(ENETRESET);
510
#endif
511
512
#ifdef ENETUNREACH
513
    ERRNO_CASE(ENETUNREACH);
514
#endif
515
516
#ifdef ENFILE
517
    ERRNO_CASE(ENFILE);
518
#endif
519
520
#ifdef ENOBUFS
521
    ERRNO_CASE(ENOBUFS);
522
#endif
523
524
#ifdef ENODATA
525
    ERRNO_CASE(ENODATA);
526
#endif
527
528
#ifdef ENODEV
529
    ERRNO_CASE(ENODEV);
530
#endif
531
532
#ifdef ENOENT
533
    ERRNO_CASE(ENOENT);
534
#endif
535
536
#ifdef ENOEXEC
537
    ERRNO_CASE(ENOEXEC);
538
#endif
539
540
#ifdef ENOLINK
541
    ERRNO_CASE(ENOLINK);
542
#endif
543
544
#ifdef ENOLCK
545
#if ENOLINK != ENOLCK
546
    ERRNO_CASE(ENOLCK);
547
#endif
548
#endif
549
550
#ifdef ENOMEM
551
    ERRNO_CASE(ENOMEM);
552
#endif
553
554
#ifdef ENOMSG
555
    ERRNO_CASE(ENOMSG);
556
#endif
557
558
#ifdef ENOPROTOOPT
559
    ERRNO_CASE(ENOPROTOOPT);
560
#endif
561
562
#ifdef ENOSPC
563
    ERRNO_CASE(ENOSPC);
564
#endif
565
566
#ifdef ENOSR
567
    ERRNO_CASE(ENOSR);
568
#endif
569
570
#ifdef ENOSTR
571
    ERRNO_CASE(ENOSTR);
572
#endif
573
574
#ifdef ENOSYS
575
    ERRNO_CASE(ENOSYS);
576
#endif
577
578
#ifdef ENOTCONN
579
    ERRNO_CASE(ENOTCONN);
580
#endif
581
582
#ifdef ENOTDIR
583
    ERRNO_CASE(ENOTDIR);
584
#endif
585
586
#ifdef ENOTEMPTY
587
#if ENOTEMPTY != EEXIST
588
    ERRNO_CASE(ENOTEMPTY);
589
#endif
590
#endif
591
592
#ifdef ENOTSOCK
593
    ERRNO_CASE(ENOTSOCK);
594
#endif
595
596
#ifdef ENOTSUP
597
    ERRNO_CASE(ENOTSUP);
598
#else
599
#ifdef EOPNOTSUPP
600
    ERRNO_CASE(EOPNOTSUPP);
601
#endif
602
#endif
603
604
#ifdef ENOTTY
605
    ERRNO_CASE(ENOTTY);
606
#endif
607
608
#ifdef ENXIO
609
    ERRNO_CASE(ENXIO);
610
#endif
611
612
#ifdef EOVERFLOW
613
    ERRNO_CASE(EOVERFLOW);
614
#endif
615
616
#ifdef EPERM
617
    ERRNO_CASE(EPERM);
618
#endif
619
620
#ifdef EPIPE
621
    ERRNO_CASE(EPIPE);
622
#endif
623
624
#ifdef EPROTO
625
    ERRNO_CASE(EPROTO);
626
#endif
627
628
#ifdef EPROTONOSUPPORT
629
    ERRNO_CASE(EPROTONOSUPPORT);
630
#endif
631
632
#ifdef EPROTOTYPE
633
    ERRNO_CASE(EPROTOTYPE);
634
#endif
635
636
#ifdef ERANGE
637
    ERRNO_CASE(ERANGE);
638
#endif
639
640
#ifdef EROFS
641
    ERRNO_CASE(EROFS);
642
#endif
643
644
#ifdef ESPIPE
645
    ERRNO_CASE(ESPIPE);
646
#endif
647
648
#ifdef ESRCH
649
    ERRNO_CASE(ESRCH);
650
#endif
651
652
#ifdef ESTALE
653
    ERRNO_CASE(ESTALE);
654
#endif
655
656
#ifdef ETIME
657
    ERRNO_CASE(ETIME);
658
#endif
659
660
#ifdef ETIMEDOUT
661
    ERRNO_CASE(ETIMEDOUT);
662
#endif
663
664
#ifdef ETXTBSY
665
    ERRNO_CASE(ETXTBSY);
666
#endif
667
668
#ifdef EXDEV
669
    ERRNO_CASE(EXDEV);
670
#endif
671
672
    default:
673
      return "";
674
  }
675
}
676
677
}  // namespace errors
678
679
void DecorateErrorStack(Environment* env,
680
                        const errors::TryCatchScope& try_catch) {
681
  Local<Value> exception = try_catch.Exception();
682
683
  if (!exception->IsObject()) return;
684
685
  Local<Object> err_obj = exception.As<Object>();
686
687
  if (IsExceptionDecorated(env, err_obj)) return;
688
689
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
690
  Local<Value> stack =
691
      err_obj->Get(env->context(), env->stack_string()).ToLocalChecked();
692
  MaybeLocal<Value> maybe_value =
693
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
694
695
  Local<Value> arrow;
696
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
697
    return;
698
  }
699
700
  if (stack.IsEmpty() || !stack->IsString()) {
701
    return;
702
  }
703
704
  Local<String> decorated_stack = String::Concat(
705
      env->isolate(),
706
      String::Concat(env->isolate(),
707
                     arrow.As<String>(),
708
                     FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
709
      stack.As<String>());
710
  err_obj->Set(env->context(), env->stack_string(), decorated_stack).FromJust();
711
  err_obj->SetPrivate(
712
      env->context(), env->decorated_private_symbol(), True(env->isolate()));
713
}
714
715
7
void FatalException(Isolate* isolate,
716
                    Local<Value> error,
717
                    Local<Message> message) {
718
7
  HandleScope scope(isolate);
719
720
7
  Environment* env = Environment::GetCurrent(isolate);
721
7
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
722
7
  Local<Object> process_object = env->process_object();
723
7
  Local<String> fatal_exception_string = env->fatal_exception_string();
724
  Local<Value> fatal_exception_function =
725
      process_object->Get(env->context(),
726
21
                          fatal_exception_string).ToLocalChecked();
727
728
7
  if (!fatal_exception_function->IsFunction()) {
729
    // Failed before the process._fatalException function was added!
730
    // this is probably pretty bad.  Nothing to do but report and exit.
731
    ReportException(env, error, message);
732
    env->Exit(6);
733
  } else {
734
7
    errors::TryCatchScope fatal_try_catch(env);
735
736
    // Do not call FatalException when _fatalException handler throws
737
7
    fatal_try_catch.SetVerbose(false);
738
739
    // This will return true if the JS layer handled it, false otherwise
740
    MaybeLocal<Value> caught = fatal_exception_function.As<Function>()->Call(
741
21
        env->context(), process_object, 1, &error);
742
743
13
    if (fatal_try_catch.HasTerminated()) return;
744
745
7
    if (fatal_try_catch.HasCaught()) {
746
      // The fatal exception function threw, so we must exit
747
      ReportException(env, fatal_try_catch);
748
      env->Exit(7);
749
750
14
    } else if (caught.ToLocalChecked()->IsFalse()) {
751
1
      ReportException(env, error, message);
752
753
      // fatal_exception_function call before may have set a new exit code ->
754
      // read it again, otherwise use default for uncaughtException 1
755
1
      Local<String> exit_code = env->exit_code_string();
756
      Local<Value> code;
757


5
      if (!process_object->Get(env->context(), exit_code).ToLocal(&code) ||
758
1
          !code->IsInt32()) {
759
        env->Exit(1);
760
      }
761
2
      env->Exit(code.As<Int32>()->Value());
762
6
    }
763
6
  }
764
}
765
766
void FatalException(const FunctionCallbackInfo<Value>& args) {
767
  Isolate* isolate = args.GetIsolate();
768
  Environment* env = Environment::GetCurrent(isolate);
769
  if (env != nullptr && env->abort_on_uncaught_exception()) {
770
    Abort();
771
  }
772
  Local<Value> exception = args[0];
773
  Local<Message> message = Exception::CreateMessage(isolate, exception);
774
  FatalException(isolate, exception, message);
775
}
776
777

492
}  // namespace node