@@ -908,6 +908,7 @@ MakeDomainCallback(const Handle<Object> object,
908908 Local<Function> exit;
909909
910910 TryCatch try_catch;
911+ try_catch.SetVerbose (true );
911912
912913 bool has_domain = domain_v->IsObject ();
913914 if (has_domain) {
@@ -922,15 +923,13 @@ MakeDomainCallback(const Handle<Object> object,
922923 enter->Call (domain, 0 , NULL );
923924
924925 if (try_catch.HasCaught ()) {
925- FatalException (try_catch);
926926 return Undefined (node_isolate);
927927 }
928928 }
929929
930930 Local<Value> ret = callback->Call (object, argc, argv);
931931
932932 if (try_catch.HasCaught ()) {
933- FatalException (try_catch);
934933 return Undefined (node_isolate);
935934 }
936935
@@ -940,7 +939,6 @@ MakeDomainCallback(const Handle<Object> object,
940939 exit->Call (domain, 0 , NULL );
941940
942941 if (try_catch.HasCaught ()) {
943- FatalException (try_catch);
944942 return Undefined (node_isolate);
945943 }
946944 }
@@ -954,7 +952,6 @@ MakeDomainCallback(const Handle<Object> object,
954952 process_tickCallback->Call (process, 0 , NULL );
955953
956954 if (try_catch.HasCaught ()) {
957- FatalException (try_catch);
958955 return Undefined (node_isolate);
959956 }
960957
@@ -981,11 +978,11 @@ MakeCallback(const Handle<Object> object,
981978 }
982979
983980 TryCatch try_catch;
981+ try_catch.SetVerbose (true );
984982
985983 Local<Value> ret = callback->Call (object, argc, argv);
986984
987985 if (try_catch.HasCaught ()) {
988- FatalException (try_catch);
989986 return Undefined (node_isolate);
990987 }
991988
@@ -998,7 +995,6 @@ MakeCallback(const Handle<Object> object,
998995 process_tickCallback->Call (process, 0 , NULL );
999996
1000997 if (try_catch.HasCaught ()) {
1001- FatalException (try_catch);
1002998 return Undefined (node_isolate);
1003999 }
10041000
@@ -1131,7 +1127,7 @@ ssize_t DecodeWrite(char *buf,
11311127 return StringBytes::Write (buf, buflen, val, encoding, NULL );
11321128}
11331129
1134- void DisplayExceptionLine (TryCatch &try_catch ) {
1130+ void DisplayExceptionLine (Handle<Message> message ) {
11351131 // Prevent re-entry into this function. For example, if there is
11361132 // a throw from a program in vm.runInThisContext(code, filename, true),
11371133 // then we want to show the original failure, not the secondary one.
@@ -1140,10 +1136,6 @@ void DisplayExceptionLine (TryCatch &try_catch) {
11401136 if (displayed_error) return ;
11411137 displayed_error = true ;
11421138
1143- HandleScope scope (node_isolate);
1144-
1145- Handle<Message> message = try_catch.Message ();
1146-
11471139 uv_tty_reset_mode ();
11481140
11491141 fprintf (stderr, " \n " );
@@ -1197,21 +1189,21 @@ void DisplayExceptionLine (TryCatch &try_catch) {
11971189}
11981190
11991191
1200- static void ReportException (TryCatch &try_catch, bool show_line ) {
1192+ static void ReportException (Handle<Value> er, Handle<Message> message ) {
12011193 HandleScope scope (node_isolate);
12021194
1203- if (show_line) DisplayExceptionLine (try_catch );
1195+ DisplayExceptionLine (message );
12041196
1205- String::Utf8Value trace (try_catch.StackTrace ());
1197+ Local<Value> trace_value (er->ToObject ()->Get (String::New (" stack" )));
1198+ String::Utf8Value trace (trace_value);
12061199
12071200 // 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 ()) {
12091202 fprintf (stderr, " %s\n " , *trace);
12101203 } else {
12111204 // this really only happens for RangeErrors, since they're the only
12121205 // kind that won't have all this info in the trace, or when non-Error
12131206 // objects are thrown manually.
1214- Local<Value> er = try_catch.Exception ();
12151207 bool isErrorObject = er->IsObject () &&
12161208 !(er->ToObject ()->Get (String::New (" message" ))->IsUndefined ()) &&
12171209 !(er->ToObject ()->Get (String::New (" name" ))->IsUndefined ());
@@ -1229,20 +1221,30 @@ static void ReportException(TryCatch &try_catch, bool show_line) {
12291221 fflush (stderr);
12301222}
12311223
1224+
1225+ static void ReportException (TryCatch& try_catch) {
1226+ ReportException (try_catch.Exception (), try_catch.Message ());
1227+ }
1228+
1229+
12321230// Executes a str within the current v8 context.
12331231Local<Value> ExecuteString (Handle<String> source, Handle<Value> filename) {
12341232 HandleScope scope (node_isolate);
12351233 TryCatch try_catch;
12361234
1235+ // try_catch must be nonverbose to disable FatalException() handler,
1236+ // we will handle exceptions ourself.
1237+ try_catch.SetVerbose (false );
1238+
12371239 Local<v8::Script> script = v8::Script::Compile (source, filename);
12381240 if (script.IsEmpty ()) {
1239- ReportException (try_catch, true );
1241+ ReportException (try_catch);
12401242 exit (3 );
12411243 }
12421244
12431245 Local<Value> result = script->Run ();
12441246 if (result.IsEmpty ()) {
1245- ReportException (try_catch, true );
1247+ ReportException (try_catch);
12461248 exit (4 );
12471249 }
12481250
@@ -1869,7 +1871,8 @@ static void OnFatalError(const char* location, const char* message) {
18691871 exit (5 );
18701872}
18711873
1872- void FatalException (TryCatch &try_catch) {
1874+
1875+ void FatalException (Handle<Value> error, Handle<Message> message) {
18731876 HandleScope scope (node_isolate);
18741877
18751878 if (fatal_exception_symbol.IsEmpty ())
@@ -1880,33 +1883,48 @@ void FatalException(TryCatch &try_catch) {
18801883 if (!fatal_v->IsFunction ()) {
18811884 // failed before the process._fatalException function was added!
18821885 // this is probably pretty bad. Nothing to do but report and exit.
1883- ReportException (try_catch, true );
1886+ ReportException (error, message );
18841887 exit (6 );
18851888 }
18861889
18871890 Local<Function> fatal_f = Local<Function>::Cast (fatal_v);
18881891
1889- Local<Value> error = try_catch.Exception ();
1890- Local<Value> argv[] = { error };
1891-
18921892 TryCatch fatal_try_catch;
18931893
1894+ // Do not call FatalException when _fatalException handler throws
1895+ fatal_try_catch.SetVerbose (false );
1896+
18941897 // 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 );
18961899
18971900 if (fatal_try_catch.HasCaught ()) {
18981901 // the fatal exception function threw, so we must exit
1899- ReportException (fatal_try_catch, true );
1902+ ReportException (fatal_try_catch);
19001903 exit (7 );
19011904 }
19021905
19031906 if (false == caught->BooleanValue ()) {
1904- ReportException (try_catch, true );
1907+ ReportException (error, message );
19051908 exit (8 );
19061909 }
19071910}
19081911
19091912
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+
19101928Persistent<Object> binding_cache;
19111929Persistent<Array> module_load_list;
19121930
@@ -2416,10 +2434,15 @@ void Load(Handle<Object> process_l) {
24162434
24172435 TryCatch try_catch;
24182436
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+
24192442 Local<Value> f_value = ExecuteString (MainSource (),
24202443 IMMUTABLE_STRING (" node.js" ));
24212444 if (try_catch.HasCaught ()) {
2422- ReportException (try_catch, true );
2445+ ReportException (try_catch);
24232446 exit (10 );
24242447 }
24252448 assert (f_value->IsFunction ());
@@ -2445,11 +2468,15 @@ void Load(Handle<Object> process_l) {
24452468 InitPerfCounters (global);
24462469#endif
24472470
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 );
24492478
2450- if (try_catch.HasCaught ()) {
2451- FatalException (try_catch);
2452- }
2479+ f->Call (global, 1 , args);
24532480}
24542481
24552482static void PrintHelp ();
@@ -2936,6 +2963,7 @@ char** Init(int argc, char *argv[]) {
29362963 uv_idle_init (uv_default_loop (), &idle_immediate_dummy);
29372964
29382965 V8::SetFatalErrorHandler (node::OnFatalError);
2966+ V8::AddMessageListener (OnMessage);
29392967
29402968 // If the --debug flag was specified then initialize the debug thread.
29412969 if (use_debug_agent) {
0 commit comments