GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_errors.cc Lines: 342 475 72.0 %
Date: 2022-08-05 04:16:08 Branches: 195 365 53.4 %

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

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

1102
    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
16
static std::string GetSourceMapErrorSource(Isolate* isolate,
53
                                           Local<Context> context,
54
                                           Local<Message> message,
55
                                           bool* added_exception_line) {
56
32
  v8::TryCatch try_catch(isolate);
57
32
  HandleScope handle_scope(isolate);
58
16
  Environment* env = Environment::GetCurrent(context);
59
60
  // The ScriptResourceName of the message may be different from the one we use
61
  // to compile the script. V8 replaces it when it detects magic comments in
62
  // the source texts.
63
16
  Local<Value> script_resource_name = message->GetScriptResourceName();
64
32
  int linenum = message->GetLineNumber(context).FromJust();
65
16
  int columnum = message->GetStartColumn(context).FromJust();
66
67
  Local<Value> argv[] = {script_resource_name,
68
                         v8::Int32::New(isolate, linenum),
69
32
                         v8::Int32::New(isolate, columnum)};
70
16
  MaybeLocal<Value> maybe_ret = env->get_source_map_error_source()->Call(
71
32
      context, Undefined(isolate), arraysize(argv), argv);
72
  Local<Value> ret;
73
16
  if (!maybe_ret.ToLocal(&ret)) {
74
    // Ignore the caught exceptions.
75
    DCHECK(try_catch.HasCaught());
76
    return std::string();
77
  }
78
32
  if (!ret->IsString()) {
79
    return std::string();
80
  }
81
16
  *added_exception_line = true;
82
16
  node::Utf8Value error_source_utf8(isolate, ret.As<String>());
83
16
  return *error_source_utf8;
84
}
85
86
939
static std::string GetErrorSource(Isolate* isolate,
87
                                  Local<Context> context,
88
                                  Local<Message> message,
89
                                  bool* added_exception_line) {
90
939
  MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
91
1878
  node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
92
1878
  std::string sourceline(*encoded_source, encoded_source.length());
93
939
  *added_exception_line = false;
94
95
939
  if (sourceline.find("node-do-not-add-exception-line") != std::string::npos) {
96
    return sourceline;
97
  }
98
99
  // If source maps have been enabled, the exception line will instead be
100
  // added in the JavaScript context:
101
939
  Environment* env = Environment::GetCurrent(isolate);
102
  const bool has_source_map_url =
103
2817
      !message->GetScriptOrigin().SourceMapUrl().IsEmpty() &&
104
2817
      !message->GetScriptOrigin().SourceMapUrl()->IsUndefined();
105


939
  if (has_source_map_url && env != nullptr && env->source_maps_enabled()) {
106
    std::string source = GetSourceMapErrorSource(
107
32
        isolate, context, message, added_exception_line);
108
16
    return *added_exception_line ? source : sourceline;
109
  }
110
111
  // Because of how node modules work, all scripts are wrapped with a
112
  // "function (module, exports, __filename, ...) {"
113
  // to provide script local variables.
114
  //
115
  // When reporting errors on the first line of a script, this wrapper
116
  // function is leaked to the user. There used to be a hack here to
117
  // truncate off the first 62 characters, but it caused numerous other
118
  // problems when vm.runIn*Context() methods were used for non-module
119
  // code.
120
  //
121
  // If we ever decide to re-instate such a hack, the following steps
122
  // must be taken:
123
  //
124
  // 1. Pass a flag around to say "this code was wrapped"
125
  // 2. Update the stack frame output so that it is also correct.
126
  //
127
  // It would probably be simpler to add a line rather than add some
128
  // number of characters to the first line, since V8 truncates the
129
  // sourceline to 78 characters, and we end up not providing very much
130
  // useful debugging info to the user if we remove 62 characters.
131
132
  // Print (filename):(line number): (message).
133
923
  ScriptOrigin origin = message->GetScriptOrigin();
134
1846
  node::Utf8Value filename(isolate, message->GetScriptResourceName());
135
923
  const char* filename_string = *filename;
136
923
  int linenum = message->GetLineNumber(context).FromJust();
137
138
923
  int script_start = (linenum - origin.LineOffset()) == 1
139
1084
                         ? origin.ColumnOffset()
140
923
                         : 0;
141
1846
  int start = message->GetStartColumn(context).FromMaybe(0);
142
923
  int end = message->GetEndColumn(context).FromMaybe(0);
143
923
  if (start >= script_start) {
144
922
    CHECK_GE(end, start);
145
922
    start -= script_start;
146
922
    end -= script_start;
147
  }
148
149
  std::string buf = SPrintF("%s:%i\n%s\n",
150
                            filename_string,
151
                            linenum,
152
1846
                            sourceline.c_str());
153
923
  CHECK_GT(buf.size(), 0);
154
923
  *added_exception_line = true;
155
156
2769
  if (start > end ||
157


1845
      start < 0 ||
158
922
      static_cast<size_t>(end) > sourceline.size()) {
159
18
    return buf;
160
  }
161
162
905
  constexpr int kUnderlineBufsize = 1020;
163
  char underline_buf[kUnderlineBufsize + 4];
164
905
  int off = 0;
165
  // Print wavy underline (GetUnderline is deprecated).
166
5212
  for (int i = 0; i < start; i++) {
167

4307
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
168
      break;
169
    }
170
4307
    CHECK_LT(off, kUnderlineBufsize);
171
4307
    underline_buf[off++] = (sourceline[i] == '\t') ? '\t' : ' ';
172
  }
173
3497
  for (int i = start; i < end; i++) {
174

2592
    if (sourceline[i] == '\0' || off >= kUnderlineBufsize) {
175
      break;
176
    }
177
2592
    CHECK_LT(off, kUnderlineBufsize);
178
2592
    underline_buf[off++] = '^';
179
  }
180
905
  CHECK_LE(off, kUnderlineBufsize);
181
905
  underline_buf[off++] = '\n';
182
183
905
  return buf + std::string(underline_buf, off);
184
}
185
186
7
void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) {
187
104
  for (int i = 0; i < stack->GetFrameCount(); i++) {
188
45
    Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
189
90
    node::Utf8Value fn_name_s(isolate, stack_frame->GetFunctionName());
190
90
    node::Utf8Value script_name(isolate, stack_frame->GetScriptName());
191
45
    const int line_number = stack_frame->GetLineNumber();
192
45
    const int column = stack_frame->GetColumn();
193
194
45
    if (stack_frame->IsEval()) {
195
      if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
196
        FPrintF(stderr, "    at [eval]:%i:%i\n", line_number, column);
197
      } else {
198
        FPrintF(stderr,
199
                "    at [eval] (%s:%i:%i)\n",
200
                *script_name,
201
                line_number,
202
                column);
203
      }
204
      break;
205
    }
206
207
45
    if (fn_name_s.length() == 0) {
208
13
      FPrintF(stderr, "    at %s:%i:%i\n", script_name, line_number, column);
209
    } else {
210
32
      FPrintF(stderr,
211
              "    at %s (%s:%i:%i)\n",
212
              fn_name_s,
213
              script_name,
214
              line_number,
215
              column);
216
    }
217
  }
218
7
  fflush(stderr);
219
7
}
220
221
424
void PrintException(Isolate* isolate,
222
                    Local<Context> context,
223
                    Local<Value> err,
224
                    Local<Message> message) {
225
  node::Utf8Value reason(isolate,
226
424
                         err->ToDetailString(context)
227
848
                             .FromMaybe(Local<String>()));
228
424
  bool added_exception_line = false;
229
  std::string source =
230
848
      GetErrorSource(isolate, context, message, &added_exception_line);
231
424
  FPrintF(stderr, "%s\n", source);
232
424
  FPrintF(stderr, "%s\n", reason);
233
234
424
  Local<v8::StackTrace> stack = message->GetStackTrace();
235
424
  if (!stack.IsEmpty()) PrintStackTrace(isolate, stack);
236
424
}
237
238
424
void PrintCaughtException(Isolate* isolate,
239
                          Local<Context> context,
240
                          const v8::TryCatch& try_catch) {
241
424
  CHECK(try_catch.HasCaught());
242
424
  PrintException(isolate, context, try_catch.Exception(), try_catch.Message());
243
424
}
244
245
582
void AppendExceptionLine(Environment* env,
246
                         Local<Value> er,
247
                         Local<Message> message,
248
                         enum ErrorHandlingMode mode) {
249
670
  if (message.IsEmpty()) return;
250
251
582
  HandleScope scope(env->isolate());
252
  Local<Object> err_obj;
253

1164
  if (!er.IsEmpty() && er->IsObject()) {
254
569
    err_obj = er.As<Object>();
255
    // If arrow_message is already set, skip.
256
    auto maybe_value = err_obj->GetPrivate(env->context(),
257
569
                                          env->arrow_message_private_symbol());
258
    Local<Value> lvalue;
259

1707
    if (!maybe_value.ToLocal(&lvalue) || lvalue->IsString())
260
67
      return;
261
  }
262
263
515
  bool added_exception_line = false;
264
  std::string source = GetErrorSource(
265
515
      env->isolate(), env->context(), message, &added_exception_line);
266
515
  if (!added_exception_line) {
267
    return;
268
  }
269
515
  MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
270
271

1030
  const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
272
  // If allocating arrow_str failed, print it out. There's not much else to do.
273
  // If it's not an error, but something needs to be printed out because
274
  // it's a fatal exception, also print it out from here.
275
  // Otherwise, the arrow property will be attached to the object and handled
276
  // by the caller.
277


685
  if (!can_set_arrow || (mode == FATAL_ERROR && !err_obj->IsNativeError())) {
278
21
    if (env->printed_error()) return;
279
21
    Mutex::ScopedLock lock(per_process::tty_mutex);
280
21
    env->set_printed_error(true);
281
282
21
    ResetStdio();
283
21
    FPrintF(stderr, "\n%s", source);
284
21
    return;
285
  }
286
287

1482
  CHECK(err_obj
288
            ->SetPrivate(env->context(),
289
                         env->arrow_message_private_symbol(),
290
                         arrow_str.ToLocalChecked())
291
            .FromMaybe(false));
292
}
293
294
[[noreturn]] void Abort() {
295
  DumpBacktrace(stderr);
296
  fflush(stderr);
297
  ABORT_NO_BACKTRACE();
298
}
299
300
[[noreturn]] void Assert(const AssertionInfo& info) {
301
  std::string name = GetHumanReadableProcessName();
302
303
  fprintf(stderr,
304
          "%s: %s:%s%s Assertion `%s' failed.\n",
305
          name.c_str(),
306
          info.file_line,
307
          info.function,
308
          *info.function ? ":" : "",
309
          info.message);
310
  fflush(stderr);
311
312
  Abort();
313
}
314
315
enum class EnhanceFatalException { kEnhance, kDontEnhance };
316
317
/**
318
 * Report the exception to the inspector, then print it to stderr.
319
 * This should only be used when the Node.js instance is about to exit
320
 * (i.e. this should be followed by a env->Exit() or an Abort()).
321
 *
322
 * Use enhance_stack = EnhanceFatalException::kDontEnhance
323
 * when it's unsafe to call into JavaScript.
324
 */
325
250
static void ReportFatalException(Environment* env,
326
                                 Local<Value> error,
327
                                 Local<Message> message,
328
                                 EnhanceFatalException enhance_stack) {
329
250
  if (!env->can_call_into_js())
330
    enhance_stack = EnhanceFatalException::kDontEnhance;
331
332
250
  Isolate* isolate = env->isolate();
333
250
  CHECK(!error.IsEmpty());
334
250
  CHECK(!message.IsEmpty());
335
500
  HandleScope scope(isolate);
336
337
250
  AppendExceptionLine(env, error, message, FATAL_ERROR);
338
339
250
  auto report_to_inspector = [&]() {
340
#if HAVE_INSPECTOR
341
250
    env->inspector_agent()->ReportUncaughtException(error, message);
342
#endif
343
250
  };
344
345
  Local<Value> arrow;
346
  Local<Value> stack_trace;
347
250
  bool decorated = IsExceptionDecorated(env, error);
348
349
250
  if (!error->IsObject()) {  // We can only enhance actual errors.
350
13
    report_to_inspector();
351
26
    stack_trace = Undefined(isolate);
352
    // If error is not an object, AppendExceptionLine() has already print the
353
    // source line and the arrow to stderr.
354
    // TODO(joyeecheung): move that side effect out of AppendExceptionLine().
355
    // It is done just to preserve the source line as soon as possible.
356
  } else {
357
237
    Local<Object> err_obj = error.As<Object>();
358
359
470
    auto enhance_with = [&](Local<Function> enhancer) {
360
      Local<Value> enhanced;
361
470
      Local<Value> argv[] = {err_obj};
362
940
      if (!enhancer.IsEmpty() &&
363
          enhancer
364
1410
              ->Call(env->context(), Undefined(isolate), arraysize(argv), argv)
365
470
              .ToLocal(&enhanced)) {
366
466
        stack_trace = enhanced;
367
      }
368
707
    };
369
370
237
    switch (enhance_stack) {
371
235
      case EnhanceFatalException::kEnhance: {
372
235
        enhance_with(env->enhance_fatal_stack_before_inspector());
373
235
        report_to_inspector();
374
235
        enhance_with(env->enhance_fatal_stack_after_inspector());
375
235
        break;
376
      }
377
2
      case EnhanceFatalException::kDontEnhance: {
378
4
        USE(err_obj->Get(env->context(), env->stack_string())
379
2
                .ToLocal(&stack_trace));
380
2
        report_to_inspector();
381
2
        break;
382
      }
383
      default:
384
        UNREACHABLE();
385
    }
386
387
    arrow =
388
237
        err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol())
389
237
            .ToLocalChecked();
390
  }
391
392
500
  node::Utf8Value trace(env->isolate(), stack_trace);
393
394
  // range errors have a trace member set to undefined
395

746
  if (trace.length() > 0 && !stack_trace->IsUndefined()) {
396


705
    if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
397
66
      FPrintF(stderr, "%s\n", trace);
398
    } else {
399
338
      node::Utf8Value arrow_string(env->isolate(), arrow);
400
169
      FPrintF(stderr, "%s\n%s\n", arrow_string, trace);
401
    }
402
  } else {
403
    // this really only happens for RangeErrors, since they're the only
404
    // kind that won't have all this info in the trace, or when non-Error
405
    // objects are thrown manually.
406
    MaybeLocal<Value> message;
407
    MaybeLocal<Value> name;
408
409
15
    if (error->IsObject()) {
410
2
      Local<Object> err_obj = error.As<Object>();
411
4
      message = err_obj->Get(env->context(), env->message_string());
412
4
      name = err_obj->Get(env->context(), env->name_string());
413
    }
414
415
4
    if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() ||
416


17
        name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) {
417
      // Not an error object. Just print as-is.
418
15
      node::Utf8Value message(env->isolate(), error);
419
420
15
      FPrintF(stderr, "%s\n",
421

30
              *message ? message.ToString() : "<toString() threw exception>");
422
    } else {
423
      node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
424
      node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());
425
426
      if (arrow.IsEmpty() || !arrow->IsString() || decorated) {
427
        FPrintF(stderr, "%s: %s\n", name_string, message_string);
428
      } else {
429
        node::Utf8Value arrow_string(env->isolate(), arrow);
430
        FPrintF(stderr,
431
            "%s\n%s: %s\n", arrow_string, name_string, message_string);
432
      }
433
    }
434
435
15
    if (!env->options()->trace_uncaught) {
436
12
      std::string argv0;
437
12
      if (!env->argv().empty()) argv0 = env->argv()[0];
438
12
      if (argv0.empty()) argv0 = "node";
439
12
      FPrintF(stderr,
440
              "(Use `%s --trace-uncaught ...` to show where the exception "
441
              "was thrown)\n",
442
24
              fs::Basename(argv0, ".exe"));
443
    }
444
  }
445
446
250
  if (env->options()->trace_uncaught) {
447
3
    Local<StackTrace> trace = message->GetStackTrace();
448
3
    if (!trace.IsEmpty()) {
449
3
      FPrintF(stderr, "Thrown at:\n");
450
3
      PrintStackTrace(env->isolate(), trace);
451
    }
452
  }
453
454
250
  if (env->options()->extra_info_on_fatal_exception) {
455
249
    FPrintF(stderr, "\nNode.js %s\n", NODE_VERSION);
456
  }
457
458
250
  fflush(stderr);
459
250
}
460
461
[[noreturn]] void FatalError(const char* location, const char* message) {
462
  OnFatalError(location, message);
463
  // to suppress compiler warning
464
  ABORT();
465
}
466
467
void OnFatalError(const char* location, const char* message) {
468
  if (location) {
469
    FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message);
470
  } else {
471
    FPrintF(stderr, "FATAL ERROR: %s\n", message);
472
  }
473
474
  Isolate* isolate = Isolate::TryGetCurrent();
475
  Environment* env = nullptr;
476
  if (isolate != nullptr) {
477
    env = Environment::GetCurrent(isolate);
478
  }
479
  bool report_on_fatalerror;
480
  {
481
    Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
482
    report_on_fatalerror = per_process::cli_options->report_on_fatalerror;
483
  }
484
485
  if (report_on_fatalerror) {
486
    report::TriggerNodeReport(
487
        isolate, env, message, "FatalError", "", Local<Object>());
488
  }
489
490
  fflush(stderr);
491
  ABORT();
492
}
493
494
1470
v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
495
    v8::Local<v8::Context> context,
496
    v8::Local<v8::Value> source,
497
    bool is_code_like) {
498
2940
  HandleScope scope(context->GetIsolate());
499
500
1470
  Environment* env = Environment::GetCurrent(context);
501
1470
  if (env->source_maps_enabled()) {
502
    // We do not expect the maybe_cache_generated_source_map to throw any more
503
    // exceptions. If it does, just ignore it.
504
4
    errors::TryCatchScope try_catch(env);
505
    Local<Function> maybe_cache_source_map =
506
2
        env->maybe_cache_generated_source_map();
507
2
    Local<Value> argv[1] = {source};
508
509
    MaybeLocal<Value> maybe_cached = maybe_cache_source_map->Call(
510
4
        context, context->Global(), arraysize(argv), argv);
511
2
    if (maybe_cached.IsEmpty()) {
512
      DCHECK(try_catch.HasCaught());
513
    }
514
  }
515
516
  Local<Value> allow_code_gen = context->GetEmbedderData(
517
2940
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings);
518
  bool codegen_allowed =
519

4410
      allow_code_gen->IsUndefined() || allow_code_gen->IsTrue();
520
  return {
521
      codegen_allowed,
522
      {},
523
1470
  };
524
}
525
526
namespace errors {
527
528
1040616
TryCatchScope::~TryCatchScope() {
529


1040622
  if (HasCaught() && !HasTerminated() && mode_ == CatchMode::kFatal) {
530
6
    HandleScope scope(env_->isolate());
531
6
    Local<v8::Value> exception = Exception();
532
6
    Local<v8::Message> message = Message();
533
6
    EnhanceFatalException enhance = CanContinue() ?
534
6
        EnhanceFatalException::kEnhance : EnhanceFatalException::kDontEnhance;
535
6
    if (message.IsEmpty())
536
      message = Exception::CreateMessage(env_->isolate(), exception);
537
6
    ReportFatalException(env_, exception, message, enhance);
538
6
    env_->Exit(7);
539
  }
540
1040616
}
541
542
8
const char* errno_string(int errorno) {
543
#define ERRNO_CASE(e)                                                          \
544
  case e:                                                                      \
545
    return #e;
546



















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

83
  if (env != nullptr && env->abort_on_uncaught_exception()) {
945
    ReportFatalException(
946
        env, exception, message, EnhanceFatalException::kEnhance);
947
    Abort();
948
  }
949
83
  bool from_promise = args[1]->IsTrue();
950
83
  errors::TriggerUncaughtException(isolate, exception, message, from_promise);
951
13
}
952
953
5314
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
954
5314
  registry->Register(SetPrepareStackTraceCallback);
955
5314
  registry->Register(SetGetSourceMapErrorSource);
956
5314
  registry->Register(SetSourceMapsEnabled);
957
5314
  registry->Register(SetMaybeCacheGeneratedSourceMap);
958
5314
  registry->Register(SetEnhanceStackForFatalException);
959
5314
  registry->Register(NoSideEffectsToString);
960
5314
  registry->Register(TriggerUncaughtException);
961
5314
}
962
963
1305
void Initialize(Local<Object> target,
964
                Local<Value> unused,
965
                Local<Context> context,
966
                void* priv) {
967
1305
  SetMethod(context,
968
            target,
969
            "setPrepareStackTraceCallback",
970
            SetPrepareStackTraceCallback);
971
1305
  SetMethod(context,
972
            target,
973
            "setGetSourceMapErrorSource",
974
            SetGetSourceMapErrorSource);
975
1305
  SetMethod(context, target, "setSourceMapsEnabled", SetSourceMapsEnabled);
976
1305
  SetMethod(context,
977
            target,
978
            "setMaybeCacheGeneratedSourceMap",
979
            SetMaybeCacheGeneratedSourceMap);
980
1305
  SetMethod(context,
981
            target,
982
            "setEnhanceStackForFatalException",
983
            SetEnhanceStackForFatalException);
984
1305
  SetMethodNoSideEffect(
985
      context, target, "noSideEffectsToString", NoSideEffectsToString);
986
1305
  SetMethod(
987
      context, target, "triggerUncaughtException", TriggerUncaughtException);
988
1305
}
989
990
321
void DecorateErrorStack(Environment* env,
991
                        const errors::TryCatchScope& try_catch) {
992
321
  Local<Value> exception = try_catch.Exception();
993
994
326
  if (!exception->IsObject()) return;
995
996
314
  Local<Object> err_obj = exception.As<Object>();
997
998
314
  if (IsExceptionDecorated(env, err_obj)) return;
999
1000
311
  AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR);
1001
311
  TryCatchScope try_catch_scope(env);  // Ignore exceptions below.
1002
622
  MaybeLocal<Value> stack = err_obj->Get(env->context(), env->stack_string());
1003
  MaybeLocal<Value> maybe_value =
1004
311
      err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol());
1005
1006
  Local<Value> arrow;
1007

933
  if (!(maybe_value.ToLocal(&arrow) && arrow->IsString())) {
1008
    return;
1009
  }
1010
1011

933
  if (stack.IsEmpty() || !stack.ToLocalChecked()->IsString()) {
1012
2
    return;
1013
  }
1014
1015
  Local<String> decorated_stack = String::Concat(
1016
      env->isolate(),
1017
      String::Concat(env->isolate(),
1018
                     arrow.As<String>(),
1019
                     FIXED_ONE_BYTE_STRING(env->isolate(), "\n")),
1020
927
      stack.ToLocalChecked().As<String>());
1021
618
  USE(err_obj->Set(env->context(), env->stack_string(), decorated_stack));
1022
  err_obj->SetPrivate(
1023
618
      env->context(), env->decorated_private_symbol(), True(env->isolate()));
1024
}
1025
1026
1535
void TriggerUncaughtException(Isolate* isolate,
1027
                              Local<Value> error,
1028
                              Local<Message> message,
1029
                              bool from_promise) {
1030
1535
  CHECK(!error.IsEmpty());
1031
1535
  HandleScope scope(isolate);
1032
1033
1535
  if (message.IsEmpty()) message = Exception::CreateMessage(isolate, error);
1034
1035
1535
  CHECK(isolate->InContext());
1036
1535
  Local<Context> context = isolate->GetCurrentContext();
1037
1535
  Environment* env = Environment::GetCurrent(context);
1038
1535
  if (env == nullptr) {
1039
    // This means that the exception happens before Environment is assigned
1040
    // to the context e.g. when there is a SyntaxError in a per-context
1041
    // script - which usually indicates that there is a bug because no JS
1042
    // error is supposed to be thrown at this point.
1043
    // Since we don't have access to Environment here, there is not
1044
    // much we can do, so we just print whatever is useful and crash.
1045
    PrintException(isolate, context, error, message);
1046
    Abort();
1047
  }
1048
1049
  // Invoke process._fatalException() to give user a chance to handle it.
1050
  // We have to grab it from the process object since this has been
1051
  // monkey-patchable.
1052
1535
  Local<Object> process_object = env->process_object();
1053
1535
  Local<String> fatal_exception_string = env->fatal_exception_string();
1054
  Local<Value> fatal_exception_function =
1055
1535
      process_object->Get(env->context(),
1056
3070
                          fatal_exception_string).ToLocalChecked();
1057
  // If the exception happens before process._fatalException is attached
1058
  // during bootstrap, or if the user has patched it incorrectly, exit
1059
  // the current Node.js instance.
1060
1535
  if (!fatal_exception_function->IsFunction()) {
1061
2
    ReportFatalException(
1062
        env, error, message, EnhanceFatalException::kDontEnhance);
1063
2
    env->Exit(6);
1064
1
    return;
1065
  }
1066
1067
  MaybeLocal<Value> maybe_handled;
1068
1533
  if (env->can_call_into_js()) {
1069
    // We do not expect the global uncaught exception itself to throw any more
1070
    // exceptions. If it does, exit the current Node.js instance.
1071
    errors::TryCatchScope try_catch(env,
1072
1527
                                    errors::TryCatchScope::CatchMode::kFatal);
1073
    // Explicitly disable verbose exception reporting -
1074
    // if process._fatalException() throws an error, we don't want it to
1075
    // trigger the per-isolate message listener which will call this
1076
    // function and recurse.
1077
1527
    try_catch.SetVerbose(false);
1078
    Local<Value> argv[2] = { error,
1079
3054
                             Boolean::New(env->isolate(), from_promise) };
1080
1081
1527
    maybe_handled = fatal_exception_function.As<Function>()->Call(
1082
1527
        env->context(), process_object, arraysize(argv), argv);
1083
  }
1084
1085
  // If process._fatalException() throws, we are now exiting the Node.js
1086
  // instance so return to continue the exit routine.
1087
  // TODO(joyeecheung): return a Maybe here to prevent the caller from
1088
  // stepping on the exit.
1089
  Local<Value> handled;
1090
1523
  if (!maybe_handled.ToLocal(&handled)) {
1091
8
    return;
1092
  }
1093
1094
  // The global uncaught exception handler returns true if the user handles it
1095
  // by e.g. listening to `uncaughtException`. In that case, continue program
1096
  // execution.
1097
  // TODO(joyeecheung): This has been only checking that the return value is
1098
  // exactly false. Investigate whether this can be turned to an "if true"
1099
  // similar to how the worker global uncaught exception handler handles it.
1100
1515
  if (!handled->IsFalse()) {
1101
1273
    return;
1102
  }
1103
1104
  // Now we are certain that the exception is fatal.
1105
242
  ReportFatalException(env, error, message, EnhanceFatalException::kEnhance);
1106
242
  RunAtExit(env);
1107
1108
  // If the global uncaught exception handler sets process.exitCode,
1109
  // exit with that code. Otherwise, exit with 1.
1110
242
  Local<String> exit_code = env->exit_code_string();
1111
  Local<Value> code;
1112

726
  if (process_object->Get(env->context(), exit_code).ToLocal(&code) &&
1113
242
      code->IsInt32()) {
1114
241
    env->Exit(code.As<Int32>()->Value());
1115
  } else {
1116
1
    env->Exit(1);
1117
  }
1118
}
1119
1120
5
void TriggerUncaughtException(Isolate* isolate, const v8::TryCatch& try_catch) {
1121
  // If the try_catch is verbose, the per-isolate message listener is going to
1122
  // handle it (which is going to call into another overload of
1123
  // TriggerUncaughtException()).
1124
5
  if (try_catch.IsVerbose()) {
1125
    return;
1126
  }
1127
1128
  // If the user calls TryCatch::TerminateExecution() on this TryCatch
1129
  // they must call CancelTerminateExecution() again before invoking
1130
  // TriggerUncaughtException() because it will invoke
1131
  // process._fatalException() in the JS land.
1132
5
  CHECK(!try_catch.HasTerminated());
1133
5
  CHECK(try_catch.HasCaught());
1134
8
  HandleScope scope(isolate);
1135
5
  TriggerUncaughtException(isolate,
1136
                           try_catch.Exception(),
1137
                           try_catch.Message(),
1138
                           false /* from_promise */);
1139
}
1140
1141
}  // namespace errors
1142
1143
}  // namespace node
1144
1145
5386
NODE_MODULE_CONTEXT_AWARE_INTERNAL(errors, node::errors::Initialize)
1146
5314
NODE_MODULE_EXTERNAL_REFERENCE(errors, node::errors::RegisterExternalReferences)