From 328aadc0ef77f51c06d657acaeba205d56e54d13 Mon Sep 17 00:00:00 2001 From: George Marques Date: Fri, 27 May 2022 09:13:25 -0300 Subject: [PATCH] GDScript: Fix stack overflow when using multiple `await` --- modules/gdscript/gdscript_function.cpp | 2 ++ modules/gdscript/gdscript_vm.cpp | 23 +++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index deef593f3410..cd3b7d69c57e 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -270,6 +270,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->exit_function(); } + + _clear_stack(); #endif } diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 8f85d8159b6a..55f4ebb1c5eb 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -3450,23 +3450,26 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time; } - // Check if this function has been interrupted by `await`. - // If that is the case we want to keep it in the debugger until it actually exits. + // Check if this is not the last time it was interrupted by `await` or if it's the first time executing. + // If that is the case then we exit the function as normal. Otherwise we postpone it until the last `await` is completed. // This ensures the call stack can be properly shown when using `await`, showing what resumed the function. - if (!awaited) { + if (!p_state || awaited) { if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->exit_function(); } +#endif + + // Free stack, except reserved addresses. + for (int i = 3; i < _stack_size; i++) { + stack[i].~Variant(); + } +#ifdef DEBUG_ENABLED } #endif - // Clear the stack even if there was an `await`. - // The stack saved in the state is a copy, so this needs to be destructed to avoid leaks. - if (_stack_size) { - // Free stack. - for (int i = 0; i < _stack_size; i++) { - stack[i].~Variant(); - } + // Always free reserved addresses, since they are never copied. + for (int i = 0; i < 3; i++) { + stack[i].~Variant(); } return retvalue;