GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_errors.cc Lines: 321 451 71.2 %
Date: 2022-07-25 04:16:17 Branches: 191 357 53.5 %

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

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

1090
    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
933
static std::string GetErrorSource(Isolate* isolate,
53
                                  Local<Context> context,
54
                                  Local<Message> message,
55
                                  bool* added_exception_line) {
56
933
  MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
57
1866
  node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
58
1866
  std::string sourceline(*encoded_source, encoded_source.length());
59
933
  *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
933
  Environment* env = Environment::GetCurrent(isolate);
64
  const bool has_source_map_url =
65
2799
      !message->GetScriptOrigin().SourceMapUrl().IsEmpty() &&
66
2799
      !message->GetScriptOrigin().SourceMapUrl()->IsUndefined();
67


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


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

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

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

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

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

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


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

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

725
  if (trace.length() > 0 && !stack_trace->IsUndefined()) {
360


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


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

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

7332
      allow_code_gen->IsUndefined() || allow_code_gen->IsTrue();
484
  return {
485
      codegen_allowed,
486
      {},
487
2444
  };
488
}
489
490
namespace errors {
491
492
1242796
TryCatchScope::~TryCatchScope() {
493


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



















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

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

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

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

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