summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2022-05-31 12:44:50 +0200
committerGitHub <noreply@github.com>2022-05-31 12:44:50 +0200
commitc881f607a90f6c6a7d8b5046ea155d881ede3ff1 (patch)
treefe162f593ec0f03f2e1b643617dbbda5374b5c53
parente633ace8c0b10f19d11ffbdc652c8139c8fd60bc (diff)
parent328aadc0ef77f51c06d657acaeba205d56e54d13 (diff)
Merge pull request #61463 from vnen/gdscript-await-stack
GDScript: Fix stack overflow when using multiple `await`
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/gdscript/gdscript_vm.cpp21
2 files changed, 14 insertions, 9 deletions
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index deef593f34..cd3b7d69c5 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 8f85d8159b..55f4ebb1c5 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
- // 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++) {
+ // Free stack, except reserved addresses.
+ for (int i = 3; i < _stack_size; i++) {
stack[i].~Variant();
}
+#ifdef DEBUG_ENABLED
+ }
+#endif
+
+ // Always free reserved addresses, since they are never copied.
+ for (int i = 0; i < 3; i++) {
+ stack[i].~Variant();
}
return retvalue;