diff options
author | George Marques <george@gmarqu.es> | 2023-02-20 14:55:13 -0300 |
---|---|---|
committer | George Marques <george@gmarqu.es> | 2023-02-20 14:55:13 -0300 |
commit | c9e49c487da86883044c5d27b79bcf3a26802765 (patch) | |
tree | 21a057571273fa0e2e2fa03260a848a753ae88d1 /modules | |
parent | 9c960a8c2494eb826a557a7ffc96dd4547f9d31e (diff) |
GDScript: Limit recursion depth for completion functions
Avoid crashing if the completion gets stuck in infinite recursion while
trying to guess the expression type.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index f79ba40e71..63dfd4d27c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1353,6 +1353,21 @@ static GDScriptCompletionIdentifier _type_from_property(const PropertyInfo &p_pr return ci; } +#define MAX_COMPLETION_RECURSION 100 +struct RecursionCheck { + int *counter; + _FORCE_INLINE_ bool check() { + return (*counter) > MAX_COMPLETION_RECURSION; + } + RecursionCheck(int *p_counter) : + counter(p_counter) { + (*counter)++; + } + ~RecursionCheck() { + (*counter)--; + } +}; + static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); @@ -1385,6 +1400,12 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, return false; } + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + if (p_expression->is_constant) { // Already has a value, so just use that. r_type = _type_from_variant(p_expression->reduced_value); @@ -1855,6 +1876,12 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + // Look in blocks first. int last_assign_line = -1; const GDScriptParser::ExpressionNode *last_assigned_expression = nullptr; @@ -2072,6 +2099,12 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + GDScriptParser::DataType base_type = p_base.type; bool is_static = base_type.is_meta_type; while (base_type.is_set()) { @@ -2285,6 +2318,12 @@ static void _find_last_return_in_block(GDScriptParser::CompletionContext &p_cont } static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + GDScriptParser::DataType base_type = p_base.type; bool is_static = base_type.is_meta_type; |