From 6f6c2dc53b1139ff47f55219c8f8e6fe2079c1f7 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Mon, 8 Jan 2024 19:55:03 +0100 Subject: [PATCH] [GDScript] Fix lifetime of call base object Ensures that the lifetime of an `Object` outlasts calls to it Also adds a check to `Object::~Object()` to check for locked state --- core/object/object.cpp | 4 +++ modules/gdscript/gdscript_compiler.cpp | 16 ++++++++++++ .../runtime/features/ref_counted_lifetime.gd | 26 +++++++++++++++++++ .../runtime/features/ref_counted_lifetime.out | 1 + 4 files changed, 47 insertions(+) create mode 100644 modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.gd create mode 100644 modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.out diff --git a/core/object/object.cpp b/core/object/object.cpp index cbf1da79fde9..60d98e9c0f0b 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -2105,6 +2105,10 @@ void Object::detach_from_objectdb() { } Object::~Object() { +#ifdef DEBUG_ENABLED + CRASH_COND_MSG(_lock_index.get() != 1, "TODO message for object."); +#endif // DEBUG_ENABLED + if (script_instance) { memdelete(script_instance); } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 99dedabd847d..cd0fbcb124fd 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -708,11 +708,27 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_call_method_bind(result, base, method, arguments); } } else { + // Make temporary if member variable and ref-counted. + if (ClassDB::is_parent_class(class_name, "RefCounted") && base.mode == GDScriptCodeGenerator::Address::MEMBER) { + GDScriptCodeGenerator::Address temp = codegen.add_temporary(base.type); + gen->write_assign(temp, base); + + base = temp; + } + gen->write_call(result, base, call->function_name, arguments); } } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); } else { + // Make temporary if member variable. + if (base.mode == GDScriptCodeGenerator::Address::MEMBER) { + GDScriptCodeGenerator::Address temp = codegen.add_temporary(base.type); + gen->write_assign(temp, base); + + base = temp; + } + gen->write_call(result, base, call->function_name, arguments); } if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { diff --git a/modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.gd b/modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.gd new file mode 100644 index 000000000000..c9d29370d019 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.gd @@ -0,0 +1,26 @@ +# https://github.com/godotengine/godot/issues/86788 + +extends Node + +class MyClassTyped: + func enter(outer): + outer.my_class_typed = MyClassTyped.new() + exit() + + func exit(): + pass + +class MyClassUnTyped: + func enter(outer): + outer.my_class_untyped = MyClassUnTyped.new() + exit() + + func exit(): + pass + +var my_class_typed := MyClassTyped.new() +var my_class_untyped = MyClassUnTyped.new() + +func test(): + my_class_typed.enter(self) + my_class_untyped.enter(self) diff --git a/modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.out b/modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.out new file mode 100644 index 000000000000..d73c5eb7cde3 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/ref_counted_lifetime.out @@ -0,0 +1 @@ +GDTEST_OK