diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 90ec4b2ffe9..37fdd8f5542 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -363,6 +363,16 @@ public: v->_get_obj().ref(r); } + // This should be used with extreme caution, as it does not increment the reference count in the + // case where the object is `RefCounted`. You *must* ensure that the destructor of this + // `Variant` is never called, and that the assigned object always outlives the `Variant`. + _FORCE_INLINE_ static void object_assign_without_ref_unsafe(Variant *v, Object *o) { + v->type = Variant::OBJECT; + Variant::ObjData &obj_data = v->_get_obj(); + obj_data.id = o->get_instance_id(); + obj_data.obj = o; + } + _FORCE_INLINE_ static void object_reset_data(Variant *v) { v->_get_obj() = Variant::ObjData(); } diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 41f205e318c..54c7da8463b 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -660,7 +660,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&stack[ADDR_STACK_SELF], Variant); script = _script; } - memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script)); + + // We must call a `Variant` constructor here, as accessing an object without doing so is undefined behavior. + memnew_placement(&stack[ADDR_STACK_CLASS], Variant); + VariantInternal::object_assign_without_ref_unsafe(&stack[ADDR_STACK_CLASS], script); + memnew_placement(&stack[ADDR_STACK_NIL], Variant); String err_text; @@ -4009,7 +4013,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GDScriptLanguage::get_singleton()->exit_function(); } - for (int i = 0; i < _stack_size; i++) { + // We deliberately avoid calling the destructor for `ADDR_STACK_CLASS`, since we initialized it + // without incrementing any reference count that it might have. + stack[ADDR_STACK_SELF].~Variant(); + stack[ADDR_STACK_NIL].~Variant(); + + for (int i = FIXED_ADDRESSES_MAX; i < _stack_size; i++) { stack[i].~Variant(); }