Skip to content

Commit dc58731

Browse files
addaleaxBethGriggs
authored andcommittedFeb 6, 2020
cli: add --trace-uncaught flag
Add a flag that makes Node.js print the stack trace at the time of *throwing* uncaught exceptions, rather than at the creation of the `Error` object, if there is any. This is disabled by default because it affects GC behavior. PR-URL: #30025 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Gireesh Punathil <[email protected]>
1 parent b560f7b commit dc58731

17 files changed

+111
-0
lines changed
 

‎doc/api/cli.md

+13
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,18 @@ added: v12.2.0
785785
Prints TLS packet trace information to `stderr`. This can be used to debug TLS
786786
connection problems.
787787

788+
### `--trace-uncaught`
789+
<!-- YAML
790+
added: REPLACEME
791+
-->
792+
793+
Print stack traces for uncaught exceptions; usually, the stack trace associated
794+
with the creation of an `Error` is printed, whereas this makes Node.js also
795+
print the stack trace associated with throwing the value (which does not need
796+
to be an `Error` instance).
797+
798+
Enabling this option may affect garbage collection behavior negatively.
799+
788800
### `--trace-warnings`
789801
<!-- YAML
790802
added: v6.0.0
@@ -1100,6 +1112,7 @@ Node.js options that are allowed are:
11001112
* `--trace-events-enabled`
11011113
* `--trace-sync-io`
11021114
* `--trace-tls`
1115+
* `--trace-uncaught`
11031116
* `--trace-warnings`
11041117
* `--track-heap-objects`
11051118
* `--unhandled-rejections`

‎doc/node.1

+12
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,18 @@ Print a stack trace whenever synchronous I/O is detected after the first turn of
352352
.It Fl -trace-tls
353353
Prints TLS packet trace information to stderr.
354354
.
355+
.It Fl -trace-uncaught
356+
Print stack traces for uncaught exceptions; usually, the stack trace associated
357+
with the creation of an
358+
.Sy Error
359+
is printed, whereas this makes Node.js also
360+
print the stack trace associated with throwing the value (which does not need
361+
to be an
362+
.Sy Error
363+
instance).
364+
.Pp
365+
Enabling this option may affect garbage collection behavior negatively.
366+
.
355367
.It Fl -trace-warnings
356368
Print stack traces for process warnings (including deprecations).
357369
.

‎src/node.cc

+2
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ int Environment::InitializeInspector(
232232
void Environment::InitializeDiagnostics() {
233233
isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
234234
Environment::BuildEmbedderGraph, this);
235+
if (options_->trace_uncaught)
236+
isolate_->SetCaptureStackTraceForUncaughtExceptions(true);
235237

236238
#if defined HAVE_DTRACE || defined HAVE_ETW
237239
InitDTrace(this);

‎src/node_errors.cc

+13
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,19 @@ static void ReportFatalException(Environment* env,
380380
"%s\n%s: %s\n", *arrow_string, *name_string, *message_string);
381381
}
382382
}
383+
384+
if (!env->options()->trace_uncaught) {
385+
PrintErrorString("(Use `node --trace-uncaught ...` to show "
386+
"where the exception was thrown)\n");
387+
}
388+
}
389+
390+
if (env->options()->trace_uncaught) {
391+
Local<StackTrace> trace = message->GetStackTrace();
392+
if (!trace.IsEmpty()) {
393+
PrintErrorString("Thrown at:\n");
394+
PrintStackTrace(env->isolate(), trace);
395+
}
383396
}
384397

385398
fflush(stderr);

‎src/node_options.cc

+4
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
498498
"prints TLS packet trace information to stderr",
499499
&EnvironmentOptions::trace_tls,
500500
kAllowedInEnvironment);
501+
AddOption("--trace-uncaught",
502+
"show stack traces for the `throw` behind uncaught exceptions",
503+
&EnvironmentOptions::trace_uncaught,
504+
kAllowedInEnvironment);
501505
AddOption("--trace-warnings",
502506
"show stack traces on process warnings",
503507
&EnvironmentOptions::trace_warnings,

‎src/node_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class EnvironmentOptions : public Options {
142142
bool trace_deprecation = false;
143143
bool trace_sync_io = false;
144144
bool trace_tls = false;
145+
bool trace_uncaught = false;
145146
bool trace_warnings = false;
146147
std::string unhandled_rejections;
147148
std::string userland_loader;

‎test/message/eval_messages.out

+2
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ ReferenceError: y is not defined
5555
var ______________________________________________; throw 10
5656
^
5757
10
58+
(Use `node --trace-uncaught ...` to show where the exception was thrown)
5859

5960
[eval]:1
6061
var ______________________________________________; throw 10
6162
^
6263
10
64+
(Use `node --trace-uncaught ...` to show where the exception was thrown)
6365
done

‎test/message/stdin_messages.out

+2
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ ReferenceError: y is not defined
6767
let ______________________________________________; throw 10
6868
^
6969
10
70+
(Use `node --trace-uncaught ...` to show where the exception was thrown)
7071

7172
[stdin]:1
7273
let ______________________________________________; throw 10
7374
^
7475
10
76+
(Use `node --trace-uncaught ...` to show where the exception was thrown)
7577
done

‎test/message/throw_error_with_getter_throw.out

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
throw { // eslint-disable-line no-throw-literal
44
^
55
[object Object]
6+
(Use `node --trace-uncaught ...` to show where the exception was thrown)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Flags: --trace-uncaught
2+
'use strict';
3+
require('../common');
4+
throw { // eslint-disable-line no-throw-literal
5+
get stack() {
6+
throw new Error('weird throw but ok');
7+
},
8+
get name() {
9+
throw new Error('weird throw but ok');
10+
},
11+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
*:4
3+
throw { // eslint-disable-line no-throw-literal
4+
^
5+
[object Object]
6+
Thrown at:
7+
at *throw_error_with_getter_throw_traced.js:*:*
8+
at Module._compile (internal/modules/cjs/loader.js:*:*)
9+
at Module._extensions..js (internal/modules/cjs/loader.js:*:*)
10+
at Module.load (internal/modules/cjs/loader.js:*:*)
11+
at Module._load (internal/modules/cjs/loader.js:*:*)
12+
at Module.runMain (internal/modules/cjs/loader.js:*:*)

‎test/message/throw_null.out

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
throw null;
44
^
55
null
6+
(Use `node --trace-uncaught ...` to show where the exception was thrown)

‎test/message/throw_null_traced.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Flags: --trace-uncaught
2+
'use strict';
3+
require('../common');
4+
5+
// eslint-disable-next-line no-throw-literal
6+
throw null;

‎test/message/throw_null_traced.out

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
*test*message*throw_null_traced.js:*
3+
throw null;
4+
^
5+
null
6+
Thrown at:
7+
at *throw_null_traced.js:*:*
8+
at Module._compile (internal/modules/cjs/loader.js:*:*)
9+
at Module._extensions..js (internal/modules/cjs/loader.js:*:*)
10+
at Module.load (internal/modules/cjs/loader.js:*:*)
11+
at Module._load (internal/modules/cjs/loader.js:*:*)
12+
at Module.runMain (internal/modules/cjs/loader.js:*:*)

‎test/message/throw_undefined.out

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
throw undefined;
44
^
55
undefined
6+
(Use `node --trace-uncaught ...` to show where the exception was thrown)
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Flags: --trace-uncaught
2+
'use strict';
3+
require('../common');
4+
5+
// eslint-disable-next-line no-throw-literal
6+
throw undefined;
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
*test*message*throw_undefined_traced.js:*
3+
throw undefined;
4+
^
5+
undefined
6+
Thrown at:
7+
at *throw_undefined_traced.js:*:*
8+
at Module._compile (internal/modules/cjs/loader.js:*:*)
9+
at Module._extensions..js (internal/modules/cjs/loader.js:*:*)
10+
at Module.load (internal/modules/cjs/loader.js:*:*)
11+
at Module._load (internal/modules/cjs/loader.js:*:*)
12+
at Module.runMain (internal/modules/cjs/loader.js:*:*)

0 commit comments

Comments
 (0)
Please sign in to comment.