summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp24
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_function.h2
-rw-r--r--modules/gdscript/gdscript_vm.cpp65
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.out6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.out6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/getter_return_type.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/getter_return_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd4
12 files changed, 121 insertions, 18 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index fe79f37454..00f8d2817a 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2563,7 +2563,7 @@ GDScriptLanguage::GDScriptLanguage() {
script_frame_time = 0;
_debug_call_stack_pos = 0;
- int dmcs = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater"), 1024);
+ int dmcs = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "512," + itos(GDScriptFunction::MAX_CALL_DEPTH - 1) + ",1"), 1024);
if (EngineDebugger::is_active()) {
//debugging enabled!
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index d0525be853..c8dfdbdd68 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -4252,18 +4252,22 @@ Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::Subscript
Array GDScriptAnalyzer::make_array_from_element_datatype(const GDScriptParser::DataType &p_element_datatype, const GDScriptParser::Node *p_source_node) {
Array array;
- Ref<Script> script_type = p_element_datatype.script_type;
- if (p_element_datatype.kind == GDScriptParser::DataType::CLASS && script_type.is_null()) {
- Error err = OK;
- Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_element_datatype.script_path, err);
- if (err) {
- push_error(vformat(R"(Error while getting cache for script "%s".)", p_element_datatype.script_path), p_source_node);
- return array;
+ if (p_element_datatype.builtin_type == Variant::OBJECT) {
+ Ref<Script> script_type = p_element_datatype.script_type;
+ if (p_element_datatype.kind == GDScriptParser::DataType::CLASS && script_type.is_null()) {
+ Error err = OK;
+ Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_element_datatype.script_path, err);
+ if (err) {
+ push_error(vformat(R"(Error while getting cache for script "%s".)", p_element_datatype.script_path), p_source_node);
+ return array;
+ }
+ script_type.reference_ptr(scr->find_class(p_element_datatype.class_type->fqcn));
}
- script_type.reference_ptr(scr->find_class(p_element_datatype.class_type->fqcn));
- }
- array.set_typed(p_element_datatype.builtin_type, p_element_datatype.native_type, script_type);
+ array.set_typed(p_element_datatype.builtin_type, p_element_datatype.native_type, script_type);
+ } else {
+ array.set_typed(p_element_datatype.builtin_type, StringName(), Variant());
+ }
return array;
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 46cd4b0d55..b34be11169 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -254,7 +254,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (codegen.script->member_indices.has(identifier)) {
if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
// Perform getter.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary();
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type);
Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
return temp;
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index f45c1f9577..2624fb8dd9 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -544,6 +544,8 @@ private:
#endif
public:
+ static constexpr int MAX_CALL_DEPTH = 2048; // Limit to try to avoid crash because of a stack overflow.
+
struct CallState {
GDScript *script = nullptr;
GDScriptInstance *instance = nullptr;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 7a11ea52f0..fd8875d8b1 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -459,6 +459,33 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
r_err.error = Callable::CallError::CALL_OK;
+ static thread_local int call_depth = 0;
+ if (unlikely(++call_depth > MAX_CALL_DEPTH)) {
+ call_depth--;
+#ifdef DEBUG_ENABLED
+ String err_file;
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->path.is_empty()) {
+ err_file = p_instance->script->path;
+ } else if (_script) {
+ err_file = _script->path;
+ }
+ if (err_file.is_empty()) {
+ err_file = "<built-in>";
+ }
+ String err_func = name;
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->name.is_empty()) {
+ err_func = p_instance->script->name + "." + err_func;
+ }
+ int err_line = _initial_line;
+ const char *err_text = "Stack overflow. Check for infinite recursion in your script.";
+ if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
+ // Debugger break did not happen.
+ _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text, false, ERR_HANDLER_SCRIPT);
+ }
+#endif
+ return _get_default_variant_for_data_type(return_type);
+ }
+
Variant retvalue;
Variant *stack = nullptr;
Variant **instruction_args = nullptr;
@@ -493,10 +520,12 @@ 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;
+ call_depth--;
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;
+ call_depth--;
return _get_default_variant_for_data_type(return_type);
} else {
defarg = _argument_count - p_argcount;
@@ -524,6 +553,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].builtin_type;
+ call_depth--;
return _get_default_variant_for_data_type(return_type);
}
if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
@@ -1244,7 +1274,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() +
@@ -1274,15 +1314,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) {
@@ -1294,7 +1345,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;
}
@@ -3582,5 +3633,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
stack[i].~Variant();
}
+ call_depth--;
+
return retvalue;
}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.gd b/modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.gd
new file mode 100644
index 0000000000..dd2708b21d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.gd
@@ -0,0 +1,7 @@
+func test():
+ var x = Node.new()
+
+ x.free()
+
+ var ok = x
+ var bad : Node = x
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.out b/modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.out
new file mode 100644
index 0000000000..679e51ed81
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/native_freed_instance.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> analyzer/errors/native_freed_instance.gd
+>> 7
+>> Trying to assign invalid previously freed instance.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.gd b/modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.gd
new file mode 100644
index 0000000000..758fbaccc9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.gd
@@ -0,0 +1,10 @@
+class A extends Node:
+ pass
+
+func test():
+ var x = A.new()
+
+ x.free()
+
+ var ok = x
+ var bad : A = x
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.out b/modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.out
new file mode 100644
index 0000000000..dec7090322
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/script_freed_instance.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> analyzer/errors/script_freed_instance.gd
+>> 10
+>> Trying to assign invalid previously freed instance.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/getter_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/getter_return_type.gd
new file mode 100644
index 0000000000..38bb7f6e9c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/getter_return_type.gd
@@ -0,0 +1,9 @@
+var Value:int = 8 :
+ get:
+ return Value
+ set(v):
+ Value = v
+
+func test():
+ var f:float = Value
+ print(int(f))
diff --git a/modules/gdscript/tests/scripts/analyzer/features/getter_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/getter_return_type.out
new file mode 100644
index 0000000000..b0cb63ef59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/getter_return_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+8
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd
index 7416ecd87a..26542a9e2f 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd
@@ -201,6 +201,10 @@ func test():
assert(str(typed_enums) == '[391]')
assert(typed_enums.get_typed_builtin() == TYPE_INT)
+ const const_enums: Array[E] = []
+ assert(const_enums.get_typed_builtin() == TYPE_INT)
+ assert(const_enums.get_typed_class_name() == &'')
+
var a := A.new()
var typed_natives: Array[RefCounted] = [a]