From a6a5ef0fd690123d8f646bca47f7ae6e2ad3bbfe Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Mon, 13 Jan 2020 21:00:07 +0100 Subject: Mono/C#: Add error checks to detect possible Reference leaks --- modules/mono/csharp_script.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'modules/mono/csharp_script.cpp') diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index c708fd412d..8a024eef13 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -159,6 +159,19 @@ void CSharpLanguage::finish() { // Clear here, after finalizing all domains to make sure there is nothing else referencing the elements. script_bindings.clear(); +#ifdef DEBUG_ENABLED + for (List::Element *E = unsafely_referenced_objects.front(); E; E = E->next()) { + const ObjectID &id = E->get(); + Object *obj = ObjectDB::get_instance(id); + + if (obj) { + ERR_PRINTS("Leaked unsafe reference to object: " + obj->get_class() + ":" + itos(id)); + } else { + ERR_PRINTS("Leaked unsafe reference to deleted object: " + itos(id)); + } + } +#endif + finalizing = false; } @@ -615,6 +628,23 @@ Vector CSharpLanguage::stack_trace_get_info(MonoObjec } #endif +void CSharpLanguage::post_unsafe_reference(Object *p_obj) { +#ifdef DEBUG_ENABLED + ObjectID id = p_obj->get_instance_id(); + ERR_FAIL_COND_MSG(unsafely_referenced_objects.find(id), "Multiple unsafe references for object: " + p_obj->get_class() + ":" + itos(id)); + unsafely_referenced_objects.push_back(id); +#endif +} + +void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) { +#ifdef DEBUG_ENABLED + ObjectID id = p_obj->get_instance_id(); + List::Element *elem = unsafely_referenced_objects.find(id); + ERR_FAIL_NULL(elem); + unsafely_referenced_objects.erase(elem); +#endif +} + void CSharpLanguage::frame() { if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) { @@ -1286,6 +1316,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) ref->reference(); + CSharpLanguage::get_singleton()->post_unsafe_reference(ref); } return true; @@ -1736,9 +1767,12 @@ bool CSharpInstance::_reference_owner_unsafe() { // See: _unreference_owner_unsafe() // May not me referenced yet, so we must use init_ref() instead of reference() - bool success = Object::cast_to(owner)->init_ref(); - unsafe_referenced = success; - return success; + if (static_cast(owner)->init_ref()) { + CSharpLanguage::get_singleton()->post_unsafe_reference(owner); + unsafe_referenced = true; + } + + return unsafe_referenced; } bool CSharpInstance::_unreference_owner_unsafe() { @@ -1759,6 +1793,7 @@ bool CSharpInstance::_unreference_owner_unsafe() { // See: _reference_owner_unsafe() // Destroying the owner here means self destructing, so we defer the owner destruction to the caller. + CSharpLanguage::get_singleton()->pre_unsafe_unreference(owner); return static_cast(owner)->unreference(); } -- cgit v1.2.3