[runtime] Fix unhandled exception fatal error message. Fixes #43410 (#3404)
[mono.git] / mono / metadata / exception.c
index 2aff26dfd53788fe5080ef51e97cbaf0b9975045..09b498ab559bdeabe7fa97e88f6c76634f203809 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <glib.h>
 #include <config.h>
+#include <mono/metadata/environment.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/exception-internals.h>
 
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-logger-internals.h>
 #include <string.h>
 
 #ifdef HAVE_EXECINFO_H
 #include <execinfo.h>
 #endif
 
+static MonoUnhandledExceptionFunc unhandled_exception_hook = NULL;
+static gpointer unhandled_exception_hook_data = NULL;
+
 /**
  * mono_exception_from_name:
  * @image: the Mono image where to look for the class
@@ -1051,3 +1056,50 @@ mono_error_set_pending_exception (MonoError *error)
        }
 }
 
+void
+mono_install_unhandled_exception_hook (MonoUnhandledExceptionFunc func, gpointer user_data)
+{
+       unhandled_exception_hook = func;
+       unhandled_exception_hook_data = user_data;
+}
+
+void
+mono_invoke_unhandled_exception_hook (MonoObject *exc)
+{
+       if (unhandled_exception_hook) {
+               unhandled_exception_hook (exc, unhandled_exception_hook_data);
+       } else {
+               MonoError inner_error;
+               MonoObject *other = NULL;
+               MonoString *str = mono_object_try_to_string (exc, &other, &inner_error);
+               char *msg = NULL;
+               
+               if (str && is_ok (&inner_error)) {
+                       msg = mono_string_to_utf8_checked (str, &inner_error);
+                       if (!is_ok (&inner_error)) {
+                               msg = g_strdup_printf ("Nested exception while formatting original exception");
+                               mono_error_cleanup (&inner_error);
+                       }
+               } else if (other) {
+                       char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
+                       char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other);
+
+                       msg = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
+                               original_backtrace, nested_backtrace);
+
+                       g_free (original_backtrace);
+                       g_free (nested_backtrace);
+               } else {
+                       msg = g_strdup ("Nested exception trying to figure out what went wrong");
+               }
+               mono_runtime_printf_err ("[ERROR] FATAL UNHANDLED EXCEPTION: %s", msg);
+               g_free (msg);
+#if defined(HOST_IOS)
+               g_assertion_message ("Terminating runtime due to unhandled exception");
+#else
+               exit (mono_environment_exitcode_get ());
+#endif
+       }
+
+       g_assert_not_reached ();
+}