GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_errors.cc Lines: 320 450 71.1 %
Date: 2022-07-21 04:16:21 Branches: 187 353 53.0 %

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

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

1088
    return maybe_value.ToLocal(&decorated) && decorated->IsTrue();
44
  }
45
13
  return false;
46
}
47
48
namespace per_process {
49
static Mutex tty_mutex;
50
}  // namespace per_process
51
52
932
static std::string GetErrorSource(Isolate* isolate,
53
                                  Local<Context> context,
54
                                  Local<Message> message,
55
                                  bool* added_exception_line) {
56
932
  MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
57
1864
  node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
58
1864
  std::string sourceline(*encoded_source, encoded_source.length());
59
932
  *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
932
  Environment* env = Environment::GetCurrent(isolate);
64
  const bool has_source_map_url =
65
1864
      !message->GetScriptOrigin().SourceMapUrl().IsEmpty();
66


932
  if (has_source_map_url && env != nullptr && env->source_maps_enabled()) {
67
19
    return sourceline;
68
  }
69
70
913
  if (sourceline.find("node-do-not-add-exception-line") != std::string::npos) {
71
    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
913
  ScriptOrigin origin = message->GetScriptOrigin();
97
1826
  node::Utf8Value filename(isolate, message->GetScriptResourceName());
98
913
  const char* filename_string = *filename;
99
913
  int linenum = message->GetLineNumber(context).FromJust();
100
101
913
  int script_start = (linenum - origin.LineOffset()) == 1
102
1071
                         ? origin.ColumnOffset()
103
913
                         : 0;
104
1826
  int start = message->GetStartColumn(context).FromMaybe(0);
105
913
  int end = message->GetEndColumn(context).FromMaybe(0);
106
913
  if (start >= script_start) {
107
912
    CHECK_GE(end, start);
108
912
    start -= script_start;
109
912
    end -= script_start;
110
  }
111
112
  std::string buf = SPrintF("%s:%i\n%s\n",
113
                            filename_string,
114
                            linenum,
115
1826
                            sourceline.c_str());
116
913
  CHECK_GT(buf.size(), 0);
117
913
  *added_exception_line = true;
118
119
2739
  if (start > end ||
120


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

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

2581
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
138
      break;
139
    }
140
2581
    CHECK_LT(off, kUnderlineBufsize);
141
2581
    underline_buf[off++] = '^';
142
  }
143
895
  CHECK_LE(off, kUnderlineBufsize);
144
895
  underline_buf[off++] = '\n';
145
146
895
  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
42
    Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
152
84
    node::Utf8Value fn_name_s(isolate, stack_frame->GetFunctionName());
153
84
    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
31
      FPrintF(stderr,
174
              "    at %s (%s:%i:%i)\n",
175
              fn_name_s,
176
              script_name,
177
              line_number,
178
              column);
179
    }
180
  }
181
6
  fflush(stderr);
182
6
}
183
184
423
void PrintException(Isolate* isolate,
185
                    Local<Context> context,
186
                    Local<Value> err,
187
                    Local<Message> message) {
188
  node::Utf8Value reason(isolate,
189
423
                         err->ToDetailString(context)
190
846
                             .FromMaybe(Local<String>()));
191
423
  bool added_exception_line = false;
192
  std::string source =
193
846
      GetErrorSource(isolate, context, message, &added_exception_line);
194
423
  FPrintF(stderr, "%s\n", source);
195
423
  FPrintF(stderr, "%s\n", reason);
196
197
423
  Local<v8::StackTrace> stack = message->GetStackTrace();
198
423
  if (!stack.IsEmpty()) PrintStackTrace(isolate, stack);
199
423
}
200
201
423
void PrintCaughtException(Isolate* isolate,
202
                          Local<Context> context,
203
                          const v8::TryCatch& try_catch) {
204
423
  CHECK(try_catch.HasCaught());
205
423
  PrintException(isolate, context, try_catch.Exception(), try_catch.Message());
206
423
}
207
208
574
void AppendExceptionLine(Environment* env,
209
                         Local<Value> er,
210
                         Local<Message> message,
211
                         enum ErrorHandlingMode mode) {
212
677
  if (message.IsEmpty()) return;
213
214
574
  HandleScope scope(env->isolate());
215
  Local<Object> err_obj;
216

1148
  if (!er.IsEmpty() && er->IsObject()) {
217
561
    err_obj = er.As<Object>();
218
    // If arrow_message is already set, skip.
219
    auto maybe_value = err_obj->GetPrivate(env->context(),
220
561
                                          env->arrow_message_private_symbol());
221
    Local<Value> lvalue;
222

1683
    if (!maybe_value.ToLocal(&lvalue) || lvalue->IsString())
223
65
      return;
224
  }
225
226
509
  bool added_exception_line = false;
227
  std::string source = GetErrorSource(
228
509
      env->isolate(), env->context(), message, &added_exception_line);
229
509
  if (!added_exception_line) {
230
19
    return;
231
  }
232
490
  MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
233
234

980
  const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
235
  // If allocating arrow_str failed, print it out. There's not much else to do.
236
  // If it's not an error, but something needs to be printed out because
237
  // it's a fatal exception, also print it out from here.
238
  // Otherwise, the arrow property will be attached to the object and handled
239
  // by the caller.
240


637
  if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
241
19
    if (env->printed_error()) return;
242
19
    Mutex::ScopedLock lock(per_process::tty_mutex);
243
19
    env->set_printed_error(true);
244
245
19
    ResetStdio();
246
19
    FPrintF(stderr, "\n%s", source);
247
19
    return;
248
  }
249
250

1413
  CHECK(err_obj
251
            ->SetPrivate(env->context(),
252
                         env->arrow_message_private_symbol(),
253
                         arrow_str.ToLocalChecked())
254
            .FromMaybe(false));
255
}
256
257
[[noreturn]] void Abort() {
258
  DumpBacktrace(stderr);
259
  fflush(stderr);
260
  ABORT_NO_BACKTRACE();
261
}
262
263
[[noreturn]] void Assert(const AssertionInfo& info) {
264
  std::string name = GetHumanReadableProcessName();
265
266
  fprintf(stderr,
267
          "%s: %s:%s%s Assertion `%s' failed.\n",
268
          name.c_str(),
269
          info.file_line,
270
          info.function,
271
          *info.function ? ":" : "",
272
          info.message);
273
  fflush(stderr);
274
275
  Abort();
276
}
277
278
enum class EnhanceFatalException { kEnhance, kDontEnhance };
279
280
/**
281
 * Report the exception to the inspector, then print it to stderr.
282
 * This should only be used when the Node.js instance is about to exit
283
 * (i.e. this should be followed by a env->Exit() or an Abort()).
284
 *
285
 * Use enhance_stack = EnhanceFatalException::kDontEnhance
286
 * when it's unsafe to call into JavaScript.
287
 */
288
242
static void ReportFatalException(Environment* env,
289
                                 Local<Value> error,
290
                                 Local<Message> message,
291
                                 EnhanceFatalException enhance_stack) {
292
242
  if (!env->can_call_into_js())
293
    enhance_stack = EnhanceFatalException::kDontEnhance;
294
295
242
  Isolate* isolate = env->isolate();
296
242
  CHECK(!error.IsEmpty());
297
242
  CHECK(!message.IsEmpty());
298
484
  HandleScope scope(isolate);
299
300
242
  AppendExceptionLine(env, error, message, FATAL_ERROR);
301
302
242
  auto report_to_inspector = [&]() {
303
#if HAVE_INSPECTOR
304
242
    env->inspector_agent()->ReportUncaughtException(error, message);
305
#endif
306
242
  };
307
308
  Local<Value> arrow;
309
  Local<Value> stack_trace;
310
242
  bool decorated = IsExceptionDecorated(env, error);
311
312
242
  if (!error->IsObject()) {  // We can only enhance actual errors.
313
13
    report_to_inspector();
314
26
    stack_trace = Undefined(isolate);
315
    // If error is not an object, AppendExceptionLine() has already print the
316
    // source line and the arrow to stderr.
317
    // TODO(joyeecheung): move that side effect out of AppendExceptionLine().
318
    // It is done just to preserve the source line as soon as possible.
319
  } else {
320
229
    Local<Object> err_obj = error.As<Object>();
321
322
454
    auto enhance_with = [&](Local<Function> enhancer) {
323
      Local<Value> enhanced;
324
454
      Local<Value> argv[] = {err_obj};
325
908
      if (!enhancer.IsEmpty() &&
326
          enhancer
327
1362
              ->Call(env->context(), Undefined(isolate), arraysize(argv), argv)
328
454
              .ToLocal(&enhanced)) {
329
450
        stack_trace = enhanced;
330
      }
331
683
    };
332
333
229
    switch (enhance_stack) {
334
227
      case EnhanceFatalException::kEnhance: {
335
227
        enhance_with(env->enhance_fatal_stack_before_inspector());
336
227
        report_to_inspector();
337
227
        enhance_with(env->enhance_fatal_stack_after_inspector());
338
227
        break;
339
      }
340
2
      case EnhanceFatalException::kDontEnhance: {
341
4
        USE(err_obj->Get(env->context(), env->stack_string())
342
2
                .ToLocal(&stack_trace));
343
2
        report_to_inspector();
344
2
        break;
345
      }
346
      default:
347
        UNREACHABLE();
348
    }
349
350
    arrow =
351
229
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
352
229
            .ToLocalChecked();
353
  }
354
355
484
  node::Utf8Value trace(env->isolate(), stack_trace);
356
357
  // range errors have a trace member set to undefined
358

722
  if (trace.length() > 0 && !stack_trace->IsUndefined()) {
359


681
    if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
360
80
      FPrintF(stderr, "%s\n", trace);
361
    } else {
362
294
      node::Utf8Value arrow_string(env->isolate(), arrow);
363
147
      FPrintF(stderr, "%s\n%s\n", arrow_string, trace);
364
    }
365
  } else {
366
    // this really only happens for RangeErrors, since they're the only
367
    // kind that won't have all this info in the trace, or when non-Error
368
    // objects are thrown manually.
369
    MaybeLocal<Value> message;
370
    MaybeLocal<Value> name;
371
372
15
    if (error->IsObject()) {
373
2
      Local<Object> err_obj = error.As<Object>();
374
4
      message = err_obj->Get(env->context(), env->message_string());
375
4
      name = err_obj->Get(env->context(), env->name_string());
376
    }
377
378
4
    if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
379


17
        name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
380
      // Not an error object. Just print as-is.
381
15
      node::Utf8Value message(env->isolate(), error);
382
383
15
      FPrintF(stderr, "%s\n",
384

30
              *message ? message.ToString() : "<toString() threw exception>");
385
    } else {
386
      node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
387
      node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());
388
389
      if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
390
        FPrintF(stderr, "%s: %s\n", name_string, message_string);
391
      } else {
392
        node::Utf8Value arrow_string(env->isolate(), arrow);
393
        FPrintF(stderr,
394
            "%s\n%s: %s\n", arrow_string, name_string, message_string);
395
      }
396
    }
397
398
15
    if (!env->options()->trace_uncaught) {
399
12
      std::string argv0;
400
12
      if (!env->argv().empty()) argv0 = env->argv()[0];
401
12
      if (argv0.empty()) argv0 = "node";
402
12
      FPrintF(stderr,
403
              "(Use `%s --trace-uncaught ...` to show where the exception "
404
              "was thrown)\n",
405
24
              fs::Basename(argv0, ".exe"));
406
    }
407
  }
408
409
242
  if (env->options()->trace_uncaught) {
410
3
    Local<StackTrace> trace = message->GetStackTrace();
411
3
    if (!trace.IsEmpty()) {
412
3
      FPrintF(stderr, "Thrown at:\n");
413
3
      PrintStackTrace(env->isolate(), trace);
414
    }
415
  }
416
417
242
  if (env->options()->extra_info_on_fatal_exception) {
418
241
    FPrintF(stderr, "\nNode.js %s\n", NODE_VERSION);
419
  }
420
421
242
  fflush(stderr);
422
242
}
423
424
[[noreturn]] void FatalError(const char* location, const char* message) {
425
  OnFatalError(location, message);
426
  // to suppress compiler warning
427
  ABORT();
428
}
429
430
void OnFatalError(const char* location, const char* message) {
431
  if (location) {
432
    FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message);
433
  } else {
434
    FPrintF(stderr, "FATAL ERROR: %s\n", message);
435
  }
436
437
  Isolate* isolate = Isolate::TryGetCurrent();
438
  Environment* env = nullptr;
439
  if (isolate != nullptr) {
440
    env = Environment::GetCurrent(isolate);
441
  }
442
  bool report_on_fatalerror;
443
  {
444
    Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
445
    report_on_fatalerror = per_process::cli_options->report_on_fatalerror;
446
  }
447
448
  if (report_on_fatalerror) {
449
    report::TriggerNodeReport(
450
        isolate, env, message, "FatalError", "", Local<Object>());
451
  }
452
453
  fflush(stderr);
454
  ABORT();
455
}
456
457
1179
v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
458
    v8::Local<v8::Context> context,
459
    v8::Local<v8::Value> source,
460
    bool is_code_like) {
461
2358
  HandleScope scope(context->GetIsolate());
462
463
1179
  Environment* env = Environment::GetCurrent(context);
464
1179
  if (env->source_maps_enabled()) {
465
    // We do not expect the maybe_cache_generated_source_map to throw any more
466
    // exceptions. If it does, just ignore it.
467
4
    errors::TryCatchScope try_catch(env);
468
    Local<Function> maybe_cache_source_map =
469
2
        env->maybe_cache_generated_source_map();
470
2
    Local<Value> argv[1] = {source};
471
472
    MaybeLocal<Value> maybe_cached = maybe_cache_source_map->Call(
473
4
        context, context->Global(), arraysize(argv), argv);
474
2
    if (maybe_cached.IsEmpty()) {
475
      DCHECK(try_catch.HasCaught());
476
    }
477
  }
478
479
  Local<Value> allow_code_gen = context->GetEmbedderData(
480
2358
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings);
481
  bool codegen_allowed =
482

3537
      allow_code_gen->IsUndefined() || allow_code_gen->IsTrue();
483
  return {
484
      codegen_allowed,
485
      {},
486
1179
  };
487
}
488
489
namespace errors {
490
491
1225408
TryCatchScope::~TryCatchScope() {
492


1225414
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
493
6
    HandleScope scope(env_->isolate());
494
6
    Local<v8::Value> exception = Exception();
495
6
    Local<v8::Message> message = Message();
496
6
    EnhanceFatalException enhance = CanContinue() ?
497
6
        EnhanceFatalException::kEnhance : EnhanceFatalException::kDontEnhance;
498
6
    if (message.IsEmpty())
499
      message = Exception::CreateMessage(env_->isolate(), exception);
500
6
    ReportFatalException(env_, exception, message, enhance);
501
6
    env_->Exit(7);
502
  }
503
1225408
}
504
505
8
const char* errno_string(int errorno) {
506
#define ERRNO_CASE(e)                                                          \
507
  case e:                                                                      \
508
    return #e;
509



















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

81
  if (env != nullptr && env->abort_on_uncaught_exception()) {
901
    ReportFatalException(
902
        env, exception, message, EnhanceFatalException::kEnhance);
903
    Abort();
904
  }
905
81
  bool from_promise = args[1]->IsTrue();
906
81
  errors::TriggerUncaughtException(isolate, exception, message, from_promise);
907
13
}
908
909
5265
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
910
5265
  registry->Register(SetPrepareStackTraceCallback);
911
5265
  registry->Register(SetSourceMapsEnabled);
912
5265
  registry->Register(SetMaybeCacheGeneratedSourceMap);
913
5265
  registry->Register(SetEnhanceStackForFatalException);
914
5265
  registry->Register(NoSideEffectsToString);
915
5265
  registry->Register(TriggerUncaughtException);
916
5265
}
917
918
1302
void Initialize(Local<Object> target,
919
                Local<Value> unused,
920
                Local<Context> context,
921
                void* priv) {
922
1302
  Environment* env = Environment::GetCurrent(context);
923
1302
  env->SetMethod(
924
      target, "setPrepareStackTraceCallback", SetPrepareStackTraceCallback);
925
1302
  env->SetMethod(target, "setSourceMapsEnabled", SetSourceMapsEnabled);
926
1302
  env->SetMethod(target,
927
                 "setMaybeCacheGeneratedSourceMap",
928
                 SetMaybeCacheGeneratedSourceMap);
929
1302
  env->SetMethod(target,
930
                 "setEnhanceStackForFatalException",
931
                 SetEnhanceStackForFatalException);
932
1302
  env->SetMethodNoSideEffect(
933
      target, "noSideEffectsToString", NoSideEffectsToString);
934
1302
  env->SetMethod(target, "triggerUncaughtException", TriggerUncaughtException);
935
1302
}
936
937
323
void DecorateErrorStack(Environment* env,
938
                        const errors::TryCatchScope& try_catch) {
939
323
  Local<Value> exception = try_catch.Exception();
940
941
328
  if (!exception->IsObject()) return;
942
943
315
  Local<Object> err_obj = exception.As<Object>();
944
945
315
  if (IsExceptionDecorated(env, err_obj)) return;
946
947
312
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
948
312
  TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
949
624
  MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
950
  MaybeLocal<Value> maybe_value =
951
312
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
952
953
  Local<Value> arrow;
954

936
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
955
    return;
956
  }
957
958

936
  if (stack.IsEmpty() || !stack.ToLocalChecked()->IsString()) {
959
2
    return;
960
  }
961
962
  Local<String> decorated_stack = String::Concat(
963
      env->isolate(),
964
      String::Concat(env->isolate(),
965
                     arrow.As<String>(),
966
                     FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
967
930
      stack.ToLocalChecked().As<String>());
968
620
  USE(err_obj->Set(env->context(), env->stack_string(), decorated_stack));
969
  err_obj->SetPrivate(
970
620
      env->context(), env->decorated_private_symbol(), True(env->isolate()));
971
}
972
973
1527
void TriggerUncaughtException(Isolate* isolate,
974
                              Local<Value> error,
975
                              Local<Message> message,
976
                              bool from_promise) {
977
1527
  CHECK(!error.IsEmpty());
978
1527
  HandleScope scope(isolate);
979
980
1527
  if (message.IsEmpty()) message = Exception::CreateMessage(isolate, error);
981
982
1527
  CHECK(isolate->InContext());
983
1527
  Local<Context> context = isolate->GetCurrentContext();
984
1527
  Environment* env = Environment::GetCurrent(context);
985
1527
  if (env == nullptr) {
986
    // This means that the exception happens before Environment is assigned
987
    // to the context e.g. when there is a SyntaxError in a per-context
988
    // script - which usually indicates that there is a bug because no JS
989
    // error is supposed to be thrown at this point.
990
    // Since we don't have access to Environment here, there is not
991
    // much we can do, so we just print whatever is useful and crash.
992
    PrintException(isolate, context, error, message);
993
    Abort();
994
  }
995
996
  // Invoke process._fatalException() to give user a chance to handle it.
997
  // We have to grab it from the process object since this has been
998
  // monkey-patchable.
999
1527
  Local<Object> process_object = env->process_object();
1000
1527
  Local<String> fatal_exception_string = env->fatal_exception_string();
1001
  Local<Value> fatal_exception_function =
1002
1527
      process_object->Get(env->context(),
1003
3054
                          fatal_exception_string).ToLocalChecked();
1004
  // If the exception happens before process._fatalException is attached
1005
  // during bootstrap, or if the user has patched it incorrectly, exit
1006
  // the current Node.js instance.
1007
1527
  if (!fatal_exception_function->IsFunction()) {
1008
2
    ReportFatalException(
1009
        env, error, message, EnhanceFatalException::kDontEnhance);
1010
2
    env->Exit(6);
1011
1
    return;
1012
  }
1013
1014
  MaybeLocal<Value> maybe_handled;
1015
1525
  if (env->can_call_into_js()) {
1016
    // We do not expect the global uncaught exception itself to throw any more
1017
    // exceptions. If it does, exit the current Node.js instance.
1018
    errors::TryCatchScope try_catch(env,
1019
1519
                                    errors::TryCatchScope::CatchMode::kFatal);
1020
    // Explicitly disable verbose exception reporting -
1021
    // if process._fatalException() throws an error, we don't want it to
1022
    // trigger the per-isolate message listener which will call this
1023
    // function and recurse.
1024
1519
    try_catch.SetVerbose(false);
1025
    Local<Value> argv[2] = { error,
1026
3038
                             Boolean::New(env->isolate(), from_promise) };
1027
1028
1519
    maybe_handled = fatal_exception_function.As<Function>()->Call(
1029
1519
        env->context(), process_object, arraysize(argv), argv);
1030
  }
1031
1032
  // If process._fatalException() throws, we are now exiting the Node.js
1033
  // instance so return to continue the exit routine.
1034
  // TODO(joyeecheung): return a Maybe here to prevent the caller from
1035
  // stepping on the exit.
1036
  Local<Value> handled;
1037
1515
  if (!maybe_handled.ToLocal(&handled)) {
1038
8
    return;
1039
  }
1040
1041
  // The global uncaught exception handler returns true if the user handles it
1042
  // by e.g. listening to `uncaughtException`. In that case, continue program
1043
  // execution.
1044
  // TODO(joyeecheung): This has been only checking that the return value is
1045
  // exactly false. Investigate whether this can be turned to an "if true"
1046
  // similar to how the worker global uncaught exception handler handles it.
1047
1507
  if (!handled->IsFalse()) {
1048
1273
    return;
1049
  }
1050
1051
  // Now we are certain that the exception is fatal.
1052
234
  ReportFatalException(env, error, message, EnhanceFatalException::kEnhance);
1053
234
  RunAtExit(env);
1054
1055
  // If the global uncaught exception handler sets process.exitCode,
1056
  // exit with that code. Otherwise, exit with 1.
1057
234
  Local<String> exit_code = env->exit_code_string();
1058
  Local<Value> code;
1059

702
  if (process_object->Get(env->context(), exit_code).ToLocal(&code) &&
1060
234
      code->IsInt32()) {
1061
233
    env->Exit(code.As<Int32>()->Value());
1062
  } else {
1063
1
    env->Exit(1);
1064
  }
1065
}
1066
1067
5
void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {
1068
  // If the try_catch is verbose, the per-isolate message listener is going to
1069
  // handle it (which is going to call into another overload of
1070
  // TriggerUncaughtException()).
1071
5
  if (try_catch.IsVerbose()) {
1072
    return;
1073
  }
1074
1075
  // If the user calls TryCatch::TerminateExecution() on this TryCatch
1076
  // they must call CancelTerminateExecution() again before invoking
1077
  // TriggerUncaughtException() because it will invoke
1078
  // process._fatalException() in the JS land.
1079
5
  CHECK(!try_catch.HasTerminated());
1080
5
  CHECK(try_catch.HasCaught());
1081
8
  HandleScope scope(isolate);
1082
5
  TriggerUncaughtException(isolate,
1083
                           try_catch.Exception(),
1084
                           try_catch.Message(),
1085
                           false /* from_promise */);
1086
}
1087
1088
}  // namespace errors
1089
1090
}  // namespace node
1091
1092
5333
NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)
1093
5265
NODE_MODULE_EXTERNAL_REFERENCE(errors, node::errors::RegisterExternalReferences)