From feb843da2b5e63a2293f6220f52b019a5fc55df5 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Fri, 12 Jan 2018 19:19:20 +0100 Subject: [PATCH 1/2] Mono: Fix starting MonoDevelop process from the wrong appdomain --- modules/mono/editor/monodevelop_instance.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/mono/editor/monodevelop_instance.cpp b/modules/mono/editor/monodevelop_instance.cpp index 0b0b36e1e3f..48a285561d8 100644 --- a/modules/mono/editor/monodevelop_instance.cpp +++ b/modules/mono/editor/monodevelop_instance.cpp @@ -35,6 +35,8 @@ void MonoDevelopInstance::execute(const Vector &p_files) { + _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) + ERR_FAIL_NULL(execute_method); ERR_FAIL_COND(gc_handle.is_null()); From bff9627dc47f12d517c96a2ba5ee929810491761 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Fri, 12 Jan 2018 19:23:11 +0100 Subject: [PATCH 2/2] Mono: Some StackTrace to StackInfo[] fixes - Sometimes `StackFrame.GetMethod()` returns null (e.g.: latest frame of a `MissingMethodException`). Still not sure what to do with that frame (maybe skip it), but at least it no longer fails. - Skip `CSharpLanguage::debug_get_current_stack_info()` if an error is printed from `GDMonoUtils::update_corlib_cache()`. - Fix crash when calling `GDMonoUtils::print_unhandled_exception(exc)` if there is no ScriptDebugger attached. --- modules/mono/csharp_script.cpp | 6 ++++- modules/mono/glue/cs_files/DebuggingUtils.cs | 6 +++++ modules/mono/mono_gd/gd_mono_utils.cpp | 24 ++++++++++++++++---- modules/mono/mono_gd/gd_mono_utils.h | 8 ++++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 8f8116e26ed..7df2043a62a 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -449,7 +449,7 @@ Vector CSharpLanguage::debug_get_current_stack_info() // Printing an error here will result in endless recursion, so we must be careful - if (!gdmono->is_runtime_initialized() && GDMono::get_singleton()->get_api_assembly()) + if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated) return Vector(); MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr()); @@ -503,6 +503,10 @@ Vector CSharpLanguage::stack_trace_get_info(MonoObjec return Vector(); } + // TODO + // what if the StackFrame method is null (method_decl is empty). should we skip this frame? + // can reproduce with a MissingMethodException on internal calls + sif.file = GDMonoMarshal::mono_string_to_godot(file_name); sif.line = file_line_num; sif.func = GDMonoMarshal::mono_string_to_godot(method_decl); diff --git a/modules/mono/glue/cs_files/DebuggingUtils.cs b/modules/mono/glue/cs_files/DebuggingUtils.cs index ced78f658d0..42ca57fbf98 100644 --- a/modules/mono/glue/cs_files/DebuggingUtils.cs +++ b/modules/mono/glue/cs_files/DebuggingUtils.cs @@ -26,6 +26,12 @@ namespace Godot MethodBase methodBase = frame.GetMethod(); + if (methodBase == null) + { + methodDecl = string.Empty; + return; + } + StringBuilder sb = new StringBuilder(); if (methodBase is MethodInfo methodInfo) diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index d02c73978e2..835a4614c12 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -44,10 +44,13 @@ namespace GDMonoUtils { MonoCache mono_cache; -#define CACHE_AND_CHECK(m_var, m_val) \ - { \ - m_var = m_val; \ - if (!m_var) ERR_PRINT("Mono Cache: Member " #m_var " is null. This is really bad!"); \ +#define CACHE_AND_CHECK(m_var, m_val) \ + { \ + m_var = m_val; \ + if (!m_var) { \ + ERR_EXPLAIN("Mono Cache: Member " #m_var " is null"); \ + ERR_FAIL(); \ + } \ } #define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val) @@ -133,6 +136,12 @@ void MonoCache::clear_members() { task_scheduler_handle = Ref(); } +void MonoCache::cleanup() { + + corlib_cache_updated = false; + godot_api_cache_updated = false; +} + #define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) void update_corlib_cache() { @@ -158,6 +167,8 @@ void update_corlib_cache() { CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); #endif + + mono_cache.corlib_cache_updated = true; } void update_godot_api_cache() { @@ -231,6 +242,8 @@ void update_godot_api_cache() { MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); mono_runtime_object_init(task_scheduler); mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); + + mono_cache.corlib_cache_updated = true; } void clear_cache() { @@ -402,6 +415,9 @@ void print_unhandled_exception(MonoObject *p_exc) { void print_unhandled_exception(MonoObject *p_exc, bool p_recursion_caution) { mono_print_unhandled_exception(p_exc); #ifdef DEBUG_ENABLED + if (!ScriptDebugger::get_singleton()) + return; + GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace); MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr()); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 597397ecedc..26664331702 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -129,10 +129,16 @@ struct MonoCache { Ref task_scheduler_handle; + bool corlib_cache_updated; + bool godot_api_cache_updated; + void clear_members(); - void cleanup() {} + void cleanup(); MonoCache() { + corlib_cache_updated = false; + godot_api_cache_updated = false; + clear_members(); } };