@@ -908,6 +908,7 @@ MakeDomainCallback(const Handle<Object> object,
908
908
Local<Function> exit;
909
909
910
910
TryCatch try_catch;
911
+ try_catch.SetVerbose (true );
911
912
912
913
bool has_domain = domain_v->IsObject ();
913
914
if (has_domain) {
@@ -922,15 +923,13 @@ MakeDomainCallback(const Handle<Object> object,
922
923
enter->Call (domain, 0 , NULL );
923
924
924
925
if (try_catch.HasCaught ()) {
925
- FatalException (try_catch);
926
926
return Undefined (node_isolate);
927
927
}
928
928
}
929
929
930
930
Local<Value> ret = callback->Call (object, argc, argv);
931
931
932
932
if (try_catch.HasCaught ()) {
933
- FatalException (try_catch);
934
933
return Undefined (node_isolate);
935
934
}
936
935
@@ -940,7 +939,6 @@ MakeDomainCallback(const Handle<Object> object,
940
939
exit->Call (domain, 0 , NULL );
941
940
942
941
if (try_catch.HasCaught ()) {
943
- FatalException (try_catch);
944
942
return Undefined (node_isolate);
945
943
}
946
944
}
@@ -954,7 +952,6 @@ MakeDomainCallback(const Handle<Object> object,
954
952
process_tickCallback->Call (process, 0 , NULL );
955
953
956
954
if (try_catch.HasCaught ()) {
957
- FatalException (try_catch);
958
955
return Undefined (node_isolate);
959
956
}
960
957
@@ -981,11 +978,11 @@ MakeCallback(const Handle<Object> object,
981
978
}
982
979
983
980
TryCatch try_catch;
981
+ try_catch.SetVerbose (true );
984
982
985
983
Local<Value> ret = callback->Call (object, argc, argv);
986
984
987
985
if (try_catch.HasCaught ()) {
988
- FatalException (try_catch);
989
986
return Undefined (node_isolate);
990
987
}
991
988
@@ -998,7 +995,6 @@ MakeCallback(const Handle<Object> object,
998
995
process_tickCallback->Call (process, 0 , NULL );
999
996
1000
997
if (try_catch.HasCaught ()) {
1001
- FatalException (try_catch);
1002
998
return Undefined (node_isolate);
1003
999
}
1004
1000
@@ -1131,7 +1127,7 @@ ssize_t DecodeWrite(char *buf,
1131
1127
return StringBytes::Write (buf, buflen, val, encoding, NULL );
1132
1128
}
1133
1129
1134
- void DisplayExceptionLine (TryCatch &try_catch ) {
1130
+ void DisplayExceptionLine (Handle<Message> message ) {
1135
1131
// Prevent re-entry into this function. For example, if there is
1136
1132
// a throw from a program in vm.runInThisContext(code, filename, true),
1137
1133
// then we want to show the original failure, not the secondary one.
@@ -1140,10 +1136,6 @@ void DisplayExceptionLine (TryCatch &try_catch) {
1140
1136
if (displayed_error) return ;
1141
1137
displayed_error = true ;
1142
1138
1143
- HandleScope scope (node_isolate);
1144
-
1145
- Handle<Message> message = try_catch.Message ();
1146
-
1147
1139
uv_tty_reset_mode ();
1148
1140
1149
1141
fprintf (stderr, " \n " );
@@ -1197,21 +1189,21 @@ void DisplayExceptionLine (TryCatch &try_catch) {
1197
1189
}
1198
1190
1199
1191
1200
- static void ReportException (TryCatch &try_catch, bool show_line ) {
1192
+ static void ReportException (Handle<Value> er, Handle<Message> message ) {
1201
1193
HandleScope scope (node_isolate);
1202
1194
1203
- if (show_line) DisplayExceptionLine (try_catch );
1195
+ DisplayExceptionLine (message );
1204
1196
1205
- String::Utf8Value trace (try_catch.StackTrace ());
1197
+ Local<Value> trace_value (er->ToObject ()->Get (String::New (" stack" )));
1198
+ String::Utf8Value trace (trace_value);
1206
1199
1207
1200
// range errors have a trace member set to undefined
1208
- if (trace.length () > 0 && !try_catch. StackTrace () ->IsUndefined ()) {
1201
+ if (trace.length () > 0 && !trace_value ->IsUndefined ()) {
1209
1202
fprintf (stderr, " %s\n " , *trace);
1210
1203
} else {
1211
1204
// this really only happens for RangeErrors, since they're the only
1212
1205
// kind that won't have all this info in the trace, or when non-Error
1213
1206
// objects are thrown manually.
1214
- Local<Value> er = try_catch.Exception ();
1215
1207
bool isErrorObject = er->IsObject () &&
1216
1208
!(er->ToObject ()->Get (String::New (" message" ))->IsUndefined ()) &&
1217
1209
!(er->ToObject ()->Get (String::New (" name" ))->IsUndefined ());
@@ -1229,20 +1221,30 @@ static void ReportException(TryCatch &try_catch, bool show_line) {
1229
1221
fflush (stderr);
1230
1222
}
1231
1223
1224
+
1225
+ static void ReportException (TryCatch& try_catch) {
1226
+ ReportException (try_catch.Exception (), try_catch.Message ());
1227
+ }
1228
+
1229
+
1232
1230
// Executes a str within the current v8 context.
1233
1231
Local<Value> ExecuteString (Handle<String> source, Handle<Value> filename) {
1234
1232
HandleScope scope (node_isolate);
1235
1233
TryCatch try_catch;
1236
1234
1235
+ // try_catch must be nonverbose to disable FatalException() handler,
1236
+ // we will handle exceptions ourself.
1237
+ try_catch.SetVerbose (false );
1238
+
1237
1239
Local<v8::Script> script = v8::Script::Compile (source, filename);
1238
1240
if (script.IsEmpty ()) {
1239
- ReportException (try_catch, true );
1241
+ ReportException (try_catch);
1240
1242
exit (3 );
1241
1243
}
1242
1244
1243
1245
Local<Value> result = script->Run ();
1244
1246
if (result.IsEmpty ()) {
1245
- ReportException (try_catch, true );
1247
+ ReportException (try_catch);
1246
1248
exit (4 );
1247
1249
}
1248
1250
@@ -1869,7 +1871,8 @@ static void OnFatalError(const char* location, const char* message) {
1869
1871
exit (5 );
1870
1872
}
1871
1873
1872
- void FatalException (TryCatch &try_catch) {
1874
+
1875
+ void FatalException (Handle<Value> error, Handle<Message> message) {
1873
1876
HandleScope scope (node_isolate);
1874
1877
1875
1878
if (fatal_exception_symbol.IsEmpty ())
@@ -1880,33 +1883,48 @@ void FatalException(TryCatch &try_catch) {
1880
1883
if (!fatal_v->IsFunction ()) {
1881
1884
// failed before the process._fatalException function was added!
1882
1885
// this is probably pretty bad. Nothing to do but report and exit.
1883
- ReportException (try_catch, true );
1886
+ ReportException (error, message );
1884
1887
exit (6 );
1885
1888
}
1886
1889
1887
1890
Local<Function> fatal_f = Local<Function>::Cast (fatal_v);
1888
1891
1889
- Local<Value> error = try_catch.Exception ();
1890
- Local<Value> argv[] = { error };
1891
-
1892
1892
TryCatch fatal_try_catch;
1893
1893
1894
+ // Do not call FatalException when _fatalException handler throws
1895
+ fatal_try_catch.SetVerbose (false );
1896
+
1894
1897
// this will return true if the JS layer handled it, false otherwise
1895
- Local<Value> caught = fatal_f->Call (process, ARRAY_SIZE (argv), argv );
1898
+ Local<Value> caught = fatal_f->Call (process, 1 , &error );
1896
1899
1897
1900
if (fatal_try_catch.HasCaught ()) {
1898
1901
// the fatal exception function threw, so we must exit
1899
- ReportException (fatal_try_catch, true );
1902
+ ReportException (fatal_try_catch);
1900
1903
exit (7 );
1901
1904
}
1902
1905
1903
1906
if (false == caught->BooleanValue ()) {
1904
- ReportException (try_catch, true );
1907
+ ReportException (error, message );
1905
1908
exit (8 );
1906
1909
}
1907
1910
}
1908
1911
1909
1912
1913
+ void FatalException (TryCatch& try_catch) {
1914
+ HandleScope scope (node_isolate);
1915
+ // TODO do not call FatalException if try_catch is verbose
1916
+ // (requires V8 API to expose getter for try_catch.is_verbose_)
1917
+ FatalException (try_catch.Exception (), try_catch.Message ());
1918
+ }
1919
+
1920
+
1921
+ void OnMessage (Handle<Message> message, Handle<Value> error) {
1922
+ // The current version of V8 sends messages for errors only
1923
+ // (thus `error` is always set).
1924
+ FatalException (error, message);
1925
+ }
1926
+
1927
+
1910
1928
Persistent<Object> binding_cache;
1911
1929
Persistent<Array> module_load_list;
1912
1930
@@ -2416,10 +2434,15 @@ void Load(Handle<Object> process_l) {
2416
2434
2417
2435
TryCatch try_catch;
2418
2436
2437
+ // Disable verbose mode to stop FatalException() handler from trying
2438
+ // to handle the exception. Errors this early in the start-up phase
2439
+ // are not safe to ignore.
2440
+ try_catch.SetVerbose (false );
2441
+
2419
2442
Local<Value> f_value = ExecuteString (MainSource (),
2420
2443
IMMUTABLE_STRING (" node.js" ));
2421
2444
if (try_catch.HasCaught ()) {
2422
- ReportException (try_catch, true );
2445
+ ReportException (try_catch);
2423
2446
exit (10 );
2424
2447
}
2425
2448
assert (f_value->IsFunction ());
@@ -2445,11 +2468,15 @@ void Load(Handle<Object> process_l) {
2445
2468
InitPerfCounters (global);
2446
2469
#endif
2447
2470
2448
- f->Call (global, 1 , args);
2471
+ // Enable handling of uncaught exceptions
2472
+ // (FatalException(), break on uncaught exception in debugger)
2473
+ //
2474
+ // This is not strictly necessary since it's almost impossible
2475
+ // to attach the debugger fast enought to break on exception
2476
+ // thrown during process startup.
2477
+ try_catch.SetVerbose (true );
2449
2478
2450
- if (try_catch.HasCaught ()) {
2451
- FatalException (try_catch);
2452
- }
2479
+ f->Call (global, 1 , args);
2453
2480
}
2454
2481
2455
2482
static void PrintHelp ();
@@ -2936,6 +2963,7 @@ char** Init(int argc, char *argv[]) {
2936
2963
uv_idle_init (uv_default_loop (), &idle_immediate_dummy);
2937
2964
2938
2965
V8::SetFatalErrorHandler (node::OnFatalError);
2966
+ V8::AddMessageListener (OnMessage);
2939
2967
2940
2968
// If the --debug flag was specified then initialize the debug thread.
2941
2969
if (use_debug_agent) {
0 commit comments