Return a correctly typed variant in case of a function error to prevent hard crashes

This commit is contained in:
SaracenOne 2022-02-17 15:18:43 +00:00
parent 5d5f80b529
commit 62d87fbd8b
2 changed files with 37 additions and 4 deletions

View File

@ -502,6 +502,8 @@ private:
List<StackDebug> stack_debug;
Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type);
_FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const;
_FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;

View File

@ -123,6 +123,34 @@ static String _get_var_type(const Variant *p_var) {
}
#endif // DEBUG_ENABLED
Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataType &p_data_type) {
if (p_data_type.kind == GDScriptDataType::BUILTIN) {
if (p_data_type.builtin_type == Variant::ARRAY) {
Array array;
// Typed array.
if (p_data_type.has_container_element_type()) {
const GDScriptDataType &element_type = p_data_type.get_container_element_type();
array.set_typed(
element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT,
element_type.native_type,
element_type.script_type);
}
return array;
} else {
Callable::CallError ce;
Variant variant;
Variant::construct(p_data_type.builtin_type, variant, nullptr, 0, ce);
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, Variant());
return variant;
}
}
return Variant();
}
String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const {
String err_text;
@ -428,7 +456,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODES_TABLE;
if (!_code_ptr) {
return Variant();
return _get_default_variant_for_data_type(return_type);
}
r_err.error = Callable::CallError::CALL_OK;
@ -467,11 +495,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_err.argument = _argument_count;
return Variant();
return _get_default_variant_for_data_type(return_type);
} else if (p_argcount < _argument_count - _default_arg_count) {
r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_err.argument = _argument_count - _default_arg_count;
return Variant();
return _get_default_variant_for_data_type(return_type);
} else {
defarg = _argument_count - p_argcount;
}
@ -498,7 +526,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_err.argument = i;
r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
return Variant();
return _get_default_variant_for_data_type(return_type);
}
if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
Variant arg;
@ -3324,6 +3352,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
#endif
// Get a default return type in case of failure
retvalue = _get_default_variant_for_data_type(return_type);
OPCODE_OUT;
}