You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
GDScript: Properly validate return type
When the type cannot be validated at compile time, the runtime must do a check to ensure type safety is kept, as the code might be assuming the return type is correct in another place, leading to crashes if the contract is broken.
This commit is contained in:
@@ -1286,8 +1286,85 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) {
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
|
||||
append(GDScriptFunction::OPCODE_RETURN, 1);
|
||||
append(p_return_value);
|
||||
if (!function->return_type.has_type || p_return_value.type.has_type) {
|
||||
// Either the function is untyped or the return value is also typed.
|
||||
|
||||
// If this is a typed function, then we need to check for potential conversions.
|
||||
if (function->return_type.has_type) {
|
||||
if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
|
||||
// Typed array.
|
||||
const GDScriptDataType &element_type = function->return_type.get_container_element_type();
|
||||
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script);
|
||||
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
|
||||
append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
|
||||
append(element_type.native_type);
|
||||
} else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) {
|
||||
// Add conversion.
|
||||
append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
|
||||
append(p_return_value);
|
||||
append(function->return_type.builtin_type);
|
||||
} else {
|
||||
// Just assign.
|
||||
append(GDScriptFunction::OPCODE_RETURN, 1);
|
||||
append(p_return_value);
|
||||
}
|
||||
} else {
|
||||
append(GDScriptFunction::OPCODE_RETURN, 1);
|
||||
append(p_return_value);
|
||||
}
|
||||
} else {
|
||||
switch (function->return_type.kind) {
|
||||
case GDScriptDataType::BUILTIN: {
|
||||
if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
|
||||
const GDScriptDataType &element_type = function->return_type.get_container_element_type();
|
||||
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script);
|
||||
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
|
||||
append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
|
||||
append(element_type.native_type);
|
||||
} else {
|
||||
append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
|
||||
append(p_return_value);
|
||||
append(function->return_type.builtin_type);
|
||||
}
|
||||
} break;
|
||||
case GDScriptDataType::NATIVE: {
|
||||
append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2);
|
||||
append(p_return_value);
|
||||
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
|
||||
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
|
||||
append(class_idx);
|
||||
} break;
|
||||
case GDScriptDataType::GDSCRIPT:
|
||||
case GDScriptDataType::SCRIPT: {
|
||||
Variant script = function->return_type.script_type;
|
||||
int script_idx = get_constant_pos(script);
|
||||
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
|
||||
|
||||
append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2);
|
||||
append(p_return_value);
|
||||
append(script_idx);
|
||||
} break;
|
||||
default: {
|
||||
ERR_PRINT("Compiler bug: unresolved return.");
|
||||
|
||||
// Shouldn't get here, but fail-safe to a regular return;
|
||||
append(GDScriptFunction::OPCODE_RETURN, 1);
|
||||
append(p_return_value);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {
|
||||
|
||||
Reference in New Issue
Block a user