You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-11 13:10:58 +00:00
Mono: Add option to keep running after unhandled exceptions
By default, an unhandled exception will cause the application to be terminated; but the project setting `mono/unhandled_exception_policy` was added to change this behaviour. The editor is hard-coded to never terminate because of unhandled exceptions, as that would make writing editor plugins a painful task, and we cannot kill the editor because of a mistake in a thirdparty plugin.
This commit is contained in:
@@ -629,7 +629,6 @@ void CSharpLanguage::frame() {
|
||||
|
||||
if (exc) {
|
||||
GDMonoUtils::debug_unhandled_exception(exc);
|
||||
GD_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,6 +283,18 @@ void GDMono::initialize() {
|
||||
|
||||
add_mono_shared_libs_dir_to_path();
|
||||
|
||||
{
|
||||
PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM,
|
||||
vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR));
|
||||
unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop);
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
// Unhandled exceptions should not terminate the editor
|
||||
unhandled_exception_policy = POLICY_LOG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
GDMonoAssembly::initialize();
|
||||
|
||||
gdmono_profiler_init();
|
||||
@@ -1063,6 +1075,8 @@ GDMono::GDMono() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
api_editor_hash = 0;
|
||||
#endif
|
||||
|
||||
unhandled_exception_policy = POLICY_TERMINATE_APP;
|
||||
}
|
||||
|
||||
GDMono::~GDMono() {
|
||||
|
||||
@@ -80,6 +80,13 @@ String to_string(Type p_type);
|
||||
|
||||
class GDMono {
|
||||
|
||||
public:
|
||||
enum UnhandledExceptionPolicy {
|
||||
POLICY_TERMINATE_APP,
|
||||
POLICY_LOG_ERROR
|
||||
};
|
||||
|
||||
private:
|
||||
bool runtime_initialized;
|
||||
bool finalizing_scripts_domain;
|
||||
|
||||
@@ -102,6 +109,8 @@ class GDMono {
|
||||
|
||||
HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
|
||||
|
||||
UnhandledExceptionPolicy unhandled_exception_policy;
|
||||
|
||||
void _domain_assemblies_cleanup(uint32_t p_domain_id);
|
||||
|
||||
bool _are_api_assemblies_out_of_sync();
|
||||
@@ -162,7 +171,9 @@ public:
|
||||
|
||||
static GDMono *get_singleton() { return singleton; }
|
||||
|
||||
static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
|
||||
GD_NORETURN static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
|
||||
|
||||
UnhandledExceptionPolicy get_unhandled_exception_policy() const { return unhandled_exception_policy; }
|
||||
|
||||
// Do not use these, unless you know what you're doing
|
||||
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
|
||||
|
||||
@@ -108,9 +108,18 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
|
||||
|
||||
void unhandled_exception(MonoException *p_exc) {
|
||||
mono_unhandled_exception((MonoObject *)p_exc); // prints the exception as well
|
||||
|
||||
if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) {
|
||||
// Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
|
||||
GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL);
|
||||
GD_UNREACHABLE();
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc);
|
||||
if (ScriptDebugger::get_singleton())
|
||||
ScriptDebugger::get_singleton()->idle_poll();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GDMonoInternals
|
||||
|
||||
@@ -45,7 +45,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
|
||||
* Do not call this function directly.
|
||||
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
|
||||
*/
|
||||
GD_NORETURN void unhandled_exception(MonoException *p_exc);
|
||||
void unhandled_exception(MonoException *p_exc);
|
||||
|
||||
} // namespace GDMonoInternals
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
#include "core/project_settings.h"
|
||||
#include "core/reference.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "editor/script_editor_debugger.h"
|
||||
#endif
|
||||
|
||||
#include "../csharp_script.h"
|
||||
#include "../utils/macros.h"
|
||||
#include "../utils/mutex_utils.h"
|
||||
@@ -596,8 +600,14 @@ void debug_print_unhandled_exception(MonoException *p_exc) {
|
||||
|
||||
void debug_send_unhandled_exception_error(MonoException *p_exc) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (!ScriptDebugger::get_singleton())
|
||||
if (!ScriptDebugger::get_singleton()) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
ERR_PRINTS(GDMonoUtils::get_exception_name_and_message(p_exc));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
_TLS_RECURSION_GUARD_;
|
||||
|
||||
@@ -621,7 +631,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
|
||||
|
||||
if (unexpected_exc) {
|
||||
GDMonoInternals::unhandled_exception(unexpected_exc);
|
||||
GD_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<ScriptLanguage::StackInfo> _si;
|
||||
@@ -655,7 +665,6 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
|
||||
|
||||
void debug_unhandled_exception(MonoException *p_exc) {
|
||||
GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well
|
||||
GD_UNREACHABLE();
|
||||
}
|
||||
|
||||
void print_unhandled_exception(MonoException *p_exc) {
|
||||
@@ -665,11 +674,9 @@ void print_unhandled_exception(MonoException *p_exc) {
|
||||
void set_pending_exception(MonoException *p_exc) {
|
||||
#ifdef NO_PENDING_EXCEPTIONS
|
||||
debug_unhandled_exception(p_exc);
|
||||
GD_UNREACHABLE();
|
||||
#else
|
||||
if (get_runtime_invoke_count() == 0) {
|
||||
debug_unhandled_exception(p_exc);
|
||||
GD_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (!mono_runtime_set_pending_exception(p_exc, false)) {
|
||||
|
||||
@@ -289,7 +289,7 @@ void set_exception_message(MonoException *p_exc, String message);
|
||||
|
||||
void debug_print_unhandled_exception(MonoException *p_exc);
|
||||
void debug_send_unhandled_exception_error(MonoException *p_exc);
|
||||
GD_NORETURN void debug_unhandled_exception(MonoException *p_exc);
|
||||
void debug_unhandled_exception(MonoException *p_exc);
|
||||
void print_unhandled_exception(MonoException *p_exc);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user