Skip to content

Commit 8892a8d

Browse files
committed
Merge pull request #109612 from dsnopek/emit-signal-no-alloca
Don't use `alloca()` in `Object::emit_signalp()` to prevent stack overflow
2 parents d98931c + 3eed536 commit 8892a8d

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

core/object/object.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,8 +1212,13 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
12121212
return ERR_CANT_ACQUIRE_RESOURCE; //no emit, signals blocked
12131213
}
12141214

1215-
Callable *slot_callables = nullptr;
1216-
uint32_t *slot_flags = nullptr;
1215+
constexpr int MAX_SLOTS_ON_STACK = 5;
1216+
// Don't default initialize the Callable objects on the stack, just reserve the space - we'll memnew_placement() them later.
1217+
alignas(Callable) uint8_t slot_callable_stack[sizeof(Callable) * MAX_SLOTS_ON_STACK];
1218+
uint32_t slot_flags_stack[MAX_SLOTS_ON_STACK];
1219+
1220+
Callable *slot_callables = (Callable *)slot_callable_stack;
1221+
uint32_t *slot_flags = slot_flags_stack;
12171222
uint32_t slot_count = 0;
12181223

12191224
{
@@ -1234,11 +1239,13 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
12341239
// which is needed in certain edge cases; e.g., https://github.com/godotengine/godot/issues/73889.
12351240
Ref<RefCounted> rc = Ref<RefCounted>(Object::cast_to<RefCounted>(this));
12361241

1242+
if (s->slot_map.size() > MAX_SLOTS_ON_STACK) {
1243+
slot_callables = (Callable *)memalloc(sizeof(Callable) * s->slot_map.size());
1244+
slot_flags = (uint32_t *)memalloc(sizeof(uint32_t) * s->slot_map.size());
1245+
}
1246+
12371247
// Ensure that disconnecting the signal or even deleting the object
12381248
// will not affect the signal calling.
1239-
slot_callables = (Callable *)alloca(sizeof(Callable) * s->slot_map.size());
1240-
slot_flags = (uint32_t *)alloca(sizeof(uint32_t) * s->slot_map.size());
1241-
12421249
for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
12431250
memnew_placement(&slot_callables[slot_count], Callable(slot_kv.value.conn.callable));
12441251
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
13081315
slot_callables[i].~Callable();
13091316
}
13101317

1318+
if (slot_callables != (Callable *)slot_callable_stack) {
1319+
memfree(slot_callables);
1320+
memfree(slot_flags);
1321+
}
1322+
13111323
return err;
13121324
}
13131325

0 commit comments

Comments
 (0)