diff options
Diffstat (limited to 'modules/gdscript/gdscript_vm.cpp')
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 65 |
1 files changed, 49 insertions, 16 deletions
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index b99f5d2685..4db41c4dfa 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -447,6 +447,9 @@ void (*type_init_function_table[])(Variant *) = { #define OP_GET_BASIS get_basis #define OP_GET_RID get_rid +#define METHOD_CALL_ON_NULL_VALUE_ERROR(method_pointer) "Cannot call method '" + (method_pointer)->get_name() + "' on a null value." +#define METHOD_CALL_ON_FREED_INSTANCE_ERROR(method_pointer) "Cannot call method '" + (method_pointer)->get_name() + "' on a previously freed instance." + Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) { OPCODES_TABLE; @@ -1241,7 +1244,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a "' to a variable of type '" + nc->get_name() + "'."; OPCODE_BREAK; } - Object *src_obj = src->operator Object *(); + + bool was_freed = false; + Object *src_obj = src->get_validated_object_with_check(was_freed); + if (!src_obj) { + if (was_freed) { + err_text = "Trying to assign invalid previously freed instance."; + } else { + err_text = "Trying to assign invalid null variable."; + } + OPCODE_BREAK; + } if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) { err_text = "Trying to assign value of type '" + src_obj->get_class_name() + @@ -1271,15 +1284,26 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } - if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) { - ScriptInstance *scr_inst = src->operator Object *()->get_script_instance(); + if (src->get_type() != Variant::NIL) { + bool was_freed = false; + Object *val_obj = src->get_validated_object_with_check(was_freed); + if (!val_obj) { + if (was_freed) { + err_text = "Trying to assign invalid previously freed instance."; + } else { + err_text = "Trying to assign invalid null variable."; + } + OPCODE_BREAK; + } + + ScriptInstance *scr_inst = val_obj->get_script_instance(); if (!scr_inst) { - err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() + + err_text = "Trying to assign value of type '" + val_obj->get_class_name() + "' to a variable of type '" + base_type->get_path().get_file() + "'."; OPCODE_BREAK; } - Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr(); + Script *src_type = val_obj->get_script_instance()->get_script().ptr(); bool valid = false; while (src_type) { @@ -1291,7 +1315,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (!valid) { - err_text = "Trying to assign value of type '" + src->operator Object *()->get_script_instance()->get_script()->get_path().get_file() + + err_text = "Trying to assign value of type '" + val_obj->get_script_instance()->get_script()->get_path().get_file() + "' to a variable of type '" + base_type->get_path().get_file() + "'."; OPCODE_BREAK; } @@ -1675,10 +1699,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool freed = false; Object *base_obj = base->get_validated_object_with_check(freed); if (freed) { - err_text = "Trying to call a function on a previously freed instance."; + err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR(method); OPCODE_BREAK; } else if (!base_obj) { - err_text = "Trying to call a function on a null value."; + err_text = METHOD_CALL_ON_NULL_VALUE_ERROR(method); OPCODE_BREAK; } #else @@ -1839,10 +1863,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool freed = false; \ Object *base_obj = base->get_validated_object_with_check(freed); \ if (freed) { \ - err_text = "Trying to call a function on a previously freed instance."; \ + err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR(method); \ OPCODE_BREAK; \ } else if (!base_obj) { \ - err_text = "Trying to call a function on a null value."; \ + err_text = METHOD_CALL_ON_NULL_VALUE_ERROR(method); \ OPCODE_BREAK; \ } \ const void **argptrs = call_args_ptr; \ @@ -1941,10 +1965,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool freed = false; Object *base_obj = base->get_validated_object_with_check(freed); if (freed) { - err_text = "Trying to call a function on a previously freed instance."; + err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR(method); OPCODE_BREAK; } else if (!base_obj) { - err_text = "Trying to call a function on a null value."; + err_text = METHOD_CALL_ON_NULL_VALUE_ERROR(method); OPCODE_BREAK; } #else @@ -1969,7 +1993,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a VariantInternal::initialize(ret, Variant::OBJECT); Object **ret_opaque = VariantInternal::get_object(ret); method->ptrcall(base_obj, argptrs, ret_opaque); - VariantInternal::update_object_id(ret); + if (method->is_return_type_raw_object_ptr()) { + // The Variant has to participate in the ref count since the method returns a raw Object *. + VariantInternal::object_assign(ret, *ret_opaque); + } else { + // The method, in case it returns something, returns an already encapsulated object. + VariantInternal::update_object_id(ret); + } #ifdef DEBUG_ENABLED if (GDScriptLanguage::get_singleton()->profiling) { @@ -1996,10 +2026,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool freed = false; Object *base_obj = base->get_validated_object_with_check(freed); if (freed) { - err_text = "Trying to call a function on a previously freed instance."; + err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR(method); OPCODE_BREAK; } else if (!base_obj) { - err_text = "Trying to call a function on a null value."; + err_text = METHOD_CALL_ON_NULL_VALUE_ERROR(method); OPCODE_BREAK; } #else @@ -3427,7 +3457,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a String message_str; if (_code_ptr[ip + 2] != 0) { GET_VARIANT_PTR(message, 1); - message_str = *message; + Variant message_var = *message; + if (message->get_type() != Variant::NIL) { + message_str = message_var; + } } if (message_str.is_empty()) { err_text = "Assertion failed."; |