From 3eed53686b0ce31ed749293054f9a3fffdae4001 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Thu, 14 Aug 2025 09:35:42 -0500 Subject: [PATCH] Don't use `alloca()` in `Object::emit_signalp()` to prevent stack overflow --- core/object/object.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/core/object/object.cpp b/core/object/object.cpp index 759525aa9d..f553872060 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1212,8 +1212,13 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked } - Callable *slot_callables = nullptr; - uint32_t *slot_flags = nullptr; + constexpr int MAX_SLOTS_ON_STACK = 5; + // Don't default initialize the Callable objects on the stack, just reserve the space - we'll memnew_placement() them later. + alignas(Callable) uint8_t slot_callable_stack[sizeof(Callable) * MAX_SLOTS_ON_STACK]; + uint32_t slot_flags_stack[MAX_SLOTS_ON_STACK]; + + Callable *slot_callables = (Callable *)slot_callable_stack; + uint32_t *slot_flags = slot_flags_stack; uint32_t slot_count = 0; { @@ -1234,11 +1239,13 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int // which is needed in certain edge cases; e.g., https://github.com/godotengine/godot/issues/73889. Ref rc = Ref(Object::cast_to(this)); + if (s->slot_map.size() > MAX_SLOTS_ON_STACK) { + slot_callables = (Callable *)memalloc(sizeof(Callable) * s->slot_map.size()); + slot_flags = (uint32_t *)memalloc(sizeof(uint32_t) * s->slot_map.size()); + } + // Ensure that disconnecting the signal or even deleting the object // will not affect the signal calling. - slot_callables = (Callable *)alloca(sizeof(Callable) * s->slot_map.size()); - slot_flags = (uint32_t *)alloca(sizeof(uint32_t) * s->slot_map.size()); - for (const KeyValue &slot_kv : s->slot_map) { memnew_placement(&slot_callables[slot_count], Callable(slot_kv.value.conn.callable)); slot_flags[slot_count] = slot_kv.value.conn.flags; @@ -1308,6 +1315,11 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int slot_callables[i].~Callable(); } + if (slot_callables != (Callable *)slot_callable_stack) { + memfree(slot_callables); + memfree(slot_flags); + } + return err; }