Repository: godot
Issue: Crash when connecting or disconnecting a signal from multiple threads
Labels: bug,topic:core,confirmed,crash

**Godot version:**
v3.2.beta.custom_build. 318c69351

**OS/device including version:**
Arch Linux, 64 bit, updated around mid-December.

**Issue description:**
When connecting to an object from multiple threads, its `slot_map` can get corrupted, leading to missing entries or crashes. I feel something similar might be possible with the `connections` list

Issue was observed by Discord user Sungray while creating multiple sprite nodes with the same texture from different threads. (Which leads to those sprites connecting to the texture's changed signal.)

**Steps to reproduce:**
Put this script on any node:
```gdscript
extends Node

signal dummy_signal()

class DummyObject extends Object:
	func dummy_method():
		pass

func _ready():
	var threads = []
	for i in range(2):
		var thread = Thread.new()
		thread.start(self, "_thread", null)
		threads.push_back(thread)

func _thread(_x):
	while true:
		var object = DummyObject.new()
		connect("dummy_signal", object, "dummy_method") # dummy method
		object.call_deferred("free") # Run the free on the main thread, locks up
		#object.free() # Run the free on the non-main thread, crashes
```
Run, should crash or enter an infinite loop on the main thread relatively fast.
When the project freezes, it should spam a errors looking like:
```
ERROR: _disconnect: Disconnecting nonexistent signal 'dummy_signal', slot: 1224:dummy_method.
   At: core/object.cpp:1526.
```
When crashing, it can generate a wide array of backtraces. Some of them are related to `malloc` or `free`, surprisingly.

<details>
<summary>No backtrace crashes (likely malloc-related) </summary>

```
handle_crash: Program crashed with signal 11
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
malloc(): invalid next->prev_inuse (unsorted)
```
```
realloc(): invalid next size
```
```
double free or corruption (!prev)
```
```
free(): corrupted unsorted chunks
```
</details>


<details>
<summary>One or more backtrace crashes</summary>

```
handle_crash: Program crashed with signal 4
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
handle_crash: Program crashed with signal 11
handle_crash: Program crashed with signal 11
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[1] /usr/lib/libc.so.6(+0x3bfb0) [0x7fa7a7b21fb0] (??:0)
[1] /usr/lib/libc.so.6(+0x3bfb0) [0x7fa7a7b21fb0] (??:0)
[1] /usr/lib/libc.so.6(+0x3bfb0) [0x7fa7a7b21fb0] (??:0)
[2] Object::Signal::Target::operator<(Object::Signal::Target const&) const (/home/bobo/Projects/godot/godot/./core/object.h:449)
[2] StringName::unref() (/home/bobo/Projects/godot/godot/./core/safe_refcount.h:118)
[2] CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::get_m(int) (/home/bobo/Projects/godot/godot/./core/cowdata.h:145)
[3] StringName::~StringName() (/home/bobo/Projects/godot/godot/core/string_name.cpp:422)
[3] VMap<Object::Signal::Target, Object::Signal::Slot>::_find_exact(Object::Signal::Target const&) const (/home/bobo/Projects/godot/godot/./core/vmap.h:104)
[3] VMap<Object::Signal::Target, Object::Signal::Slot>::operator[](Object::Signal::Target const&) (/home/bobo/Projects/godot/godot/./core/vmap.h:202)
[4] Object::Connection::~Connection() (/home/bobo/Projects/godot/godot/./core/object.h:412)
[4] VMap<Object::Signal::Target, Object::Signal::Slot>::has(Object::Signal::Target const&) const (/home/bobo/Projects/godot/godot/./core/vmap.h:131)
[4] Object::connect(StringName const&, Object*, StringName const&, Vector<Variant> const&, unsigned int) (/home/bobo/Projects/godot/godot/core/object.cpp:1485)
[5] Object::Signal::Slot::~Slot() (/home/bobo/Projects/godot/godot/./core/object.h:458)
[5] MethodBind5R<Object, Error, StringName const&, Object*, StringName const&, Vector<Variant> const&, unsigned int>::call(Object*, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/method_bind.gen.inc:4285)
[5] Object::_disconnect(StringName const&, Object*, StringName const&, bool) (/home/bobo/Projects/godot/godot/core/object.cpp:1526)
[6] VMap<Object::Signal::Target, Object::Signal::Slot>::Pair::~Pair() (/home/bobo/Projects/godot/godot/./core/vmap.h:40)
[6] Object::~Object() (/home/bobo/Projects/godot/godot/core/object.cpp:1974)
[6] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:921)
[7] void memdelete<Object>(Object*) (/home/bobo/Projects/godot/godot/./core/os/memory.h:117)
[7] CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::resize(int) (/home/bobo/Projects/godot/godot/./core/cowdata.h:304)
[7] Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/variant_call.cpp:1112)
[8] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:893)
[8] CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::insert(int, VMap<Object::Signal::Target, Object::Signal::Slot>::Pair const&) (/home/bobo/Projects/godot/godot/./core/cowdata.h:175)
[8] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Variant::CallError&, GDScriptFunction::CallState*) (/home/bobo/Projects/godot/godot/modules/gdscript/gdscript_function.cpp:1081)
[9] GDScriptInstance::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/modules/gdscript/gdscript.cpp:1173)
[9] MessageQueue::_call_function(Object*, StringName const&, Variant const*, int, bool) (/home/bobo/Projects/godot/godot/core/message_queue.cpp:250)
[9] VMap<Object::Signal::Target, Object::Signal::Slot>::insert(Object::Signal::Target const&, Object::Signal::Slot const&) (/home/bobo/Projects/godot/godot/./core/vmap.h:125)
[10] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:900)
[10] MessageQueue::flush() (/home/bobo/Projects/godot/godot/core/message_queue.cpp:299)
[10] VMap<Object::Signal::Target, Object::Signal::Slot>::operator[](Object::Signal::Target const&) (/home/bobo/Projects/godot/godot/./core/vmap.h:199)
[11] SceneTree::iteration(float) (/home/bobo/Projects/godot/godot/scene/main/scene_tree.cpp:485)
[11] _Thread::_start_func(void*) (/home/bobo/Projects/godot/godot/core/bind/core_bind.cpp:2660)
[11] Object::connect(StringName const&, Object*, StringName const&, Vector<Variant> const&, unsigned int) (/home/bobo/Projects/godot/godot/core/object.cpp:1485)
[12] Main::iteration() (/home/bobo/Projects/godot/godot/main/main.cpp:1987)
[13] OS_X11::run() (/home/bobo/Projects/godot/godot/platform/x11/os_x11.cpp:3255)
[12] ThreadPosix::thread_callback(void*) (/home/bobo/Projects/godot/godot/drivers/unix/thread_posix.cpp:76)
[14] godot3.dbg(main+0x1a3) [0x178b5f3] (/home/bobo/Projects/godot/godot/platform/x11/godot_x11.cpp:56)
[13] /usr/lib/libpthread.so.0(+0x94cf) [0x7fa7a80074cf] (??:0)
[15] /usr/lib/libc.so.6(__libc_start_main+0xf3) [0x7fa7a7b0d153] (??:0)
[14] /usr/lib/libc.so.6(clone+0x43) [0x7fa7a7be52d3] (??:0)
-- END OF BACKTRACE --
```
```
handle_crash: Program crashed with signal 11
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[2] CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::get_m(int) (/home/bobo/Projects/godot/godot/./core/cowdata.h:145)
[1] /usr/lib/libc.so.6(+0x3bfb0) [0x7f2df29e5fb0] (??:0)
Failed method: Object:free target ID: 44863
Object was deleted while awaiting a callback # Repeated many times

## This one is fishy -- probably one of the threads crashed, while the other continued working and spamming the message queue.
```

Without deferring `free`:

```
handle_crash: Program crashed with signal 11
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[1] /usr/lib/libc.so.6(+0x3bfb0) [0x7f523442dfb0] (??:0)
[2] Object::Signal::Target::operator<(Object::Signal::Target const&) const (/home/bobo/Projects/godot/godot/./core/object.h:449)
[3] VMap<Object::Signal::Target, Object::Signal::Slot>::_find_exact(Object::Signal::Target const&) const (/home/bobo/Projects/godot/godot/./core/vmap.h:104)
[4] VMap<Object::Signal::Target, Object::Signal::Slot>::has(Object::Signal::Target const&) const (/home/bobo/Projects/godot/godot/./core/vmap.h:131)
[5] Object::_disconnect(StringName const&, Object*, StringName const&, bool) (/home/bobo/Projects/godot/godot/core/object.cpp:1526)
[6] Object::~Object() (/home/bobo/Projects/godot/godot/core/object.cpp:1974)
[7] void memdelete<Object>(Object*) (/home/bobo/Projects/godot/godot/./core/os/memory.h:117)
[8] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:893)
[9] Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/variant_call.cpp:1112)
[10] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Variant::CallError&, GDScriptFunction::CallState*) (/home/bobo/Projects/godot/godot/modules/gdscript/gdscript_function.cpp:1081)
[11] GDScriptInstance::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/modules/gdscript/gdscript.cpp:1173)
[12] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:900)
[13] _Thread::_start_func(void*) (/home/bobo/Projects/godot/godot/core/bind/core_bind.cpp:2660)
[14] ThreadPosix::thread_callback(void*) (/home/bobo/Projects/godot/godot/drivers/unix/thread_posix.cpp:76)
[15] /usr/lib/libpthread.so.0(+0x94cf) [0x7f52349134cf] (??:0)
[16] /usr/lib/libc.so.6(clone+0x43) [0x7f52344f12d3] (??:0)
-- END OF BACKTRACE --
```

```
ERROR: _find: low > high, this may be a bug
   At: ./core/vmap.h:70.
handle_crash: Program crashed with signal 11
Dumping the backtrace. Please include this when reporting the bug on https://github.com/godotengine/godot/issues
[1] /usr/lib/libc.so.6(+0x3bfb0) [0x7f9a19eadfb0] (??:0)
[2] StringName::operator=(StringName const&) (/home/bobo/Projects/godot/godot/./core/safe_refcount.h:107)
[3] Object::Connection::operator=(Object::Connection const&) (/home/bobo/Projects/godot/godot/./core/object.h:412)
[4] Object::Signal::Slot::operator=(Object::Signal::Slot const&) (/home/bobo/Projects/godot/godot/./core/object.h:458)
[5] VMap<Object::Signal::Target, Object::Signal::Slot>::Pair::operator=(VMap<Object::Signal::Target, Object::Signal::Slot>::Pair const&) (/home/bobo/Projects/godot/godot/./core/vmap.h:40)
[6] CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::remove(int) (/home/bobo/Projects/godot/godot/./core/cowdata.h:164)
[7] VMap<Object::Signal::Target, Object::Signal::Slot>::erase(Object::Signal::Target const&) (/home/bobo/Projects/godot/godot/./core/vmap.h:140)
[8] Object::_disconnect(StringName const&, Object*, StringName const&, bool) (/home/bobo/Projects/godot/godot/core/object.cpp:1538)
[9] Object::~Object() (/home/bobo/Projects/godot/godot/core/object.cpp:1974)
[10] void memdelete<Object>(Object*) (/home/bobo/Projects/godot/godot/./core/os/memory.h:117)
[11] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:893)
[12] Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/variant_call.cpp:1112)
[13] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Variant::CallError&, GDScriptFunction::CallState*) (/home/bobo/Projects/godot/godot/modules/gdscript/gdscript_function.cpp:1081)
[14] GDScriptInstance::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/modules/gdscript/gdscript.cpp:1173)
[15] Object::call(StringName const&, Variant const**, int, Variant::CallError&) (/home/bobo/Projects/godot/godot/core/object.cpp:900)
[16] _Thread::_start_func(void*) (/home/bobo/Projects/godot/godot/core/bind/core_bind.cpp:2660)
[17] ThreadPosix::thread_callback(void*) (/home/bobo/Projects/godot/godot/drivers/unix/thread_posix.cpp:76)
[18] /usr/lib/libpthread.so.0(+0x94cf) [0x7f9a1a3934cf] (??:0)
[19] /usr/lib/libc.so.6(clone+0x43) [0x7f9a19f712d3] (??:0)
-- END OF BACKTRACE --
```
```
(gdb) bt
#0  0x00000000046840c8 in atomic_conditional_increment<unsigned int> (pw=0x20051) at ./core/safe_refcount.h:107
#1  SafeRefCount::ref (this=0x20051) at ./core/safe_refcount.h:182
#2  StringName::StringName (this=0x7fffcc001158, p_name=...) at core/string_name.cpp:173
#3  0x0000000002d71d6b in Object::Connection::Connection (this=0x7fffcc001140) at ./core/object.h:412
#4  0x000000000462541d in Object::Signal::Slot::Slot (this=0x7fffcc001138) at ./core/object.h:458
#5  0x000000000462536f in VMap<Object::Signal::Target, Object::Signal::Slot>::Pair::Pair (this=0x7fffcc001128) at ./core/vmap.h:40
#6  0x0000000004625279 in CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::_copy_on_write (this=0x7fffcc000f60)
    at ./core/cowdata.h:241
#7  0x00000000046261de in CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::set (this=0x7fffcc000f60, p_index=1, 
    p_elem=...) at ./core/cowdata.h:139
#8  0x0000000004625bb5 in CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::insert (this=0x7fffcc000f60, p_pos=1, 
    p_val=...) at ./core/cowdata.h:178
#9  0x000000000462585d in VMap<Object::Signal::Target, Object::Signal::Slot>::insert (this=0x7fffcc000f60, p_key=..., p_val=...)
    at ./core/vmap.h:125
#10 0x00000000046220e6 in VMap<Object::Signal::Target, Object::Signal::Slot>::operator[] (this=0x7fffcc000f60, p_key=...)
    at ./core/vmap.h:199
#11 0x000000000461a406 in Object::connect (this=0x6f9f170, p_signal=..., p_to_object=0x7fffcc000b90, p_to_method=..., p_binds=..., 
    p_flags=0) at core/object.cpp:1485
#12 0x0000000004630e8f in MethodBind5R<Object, Error, StringName const&, Object*, StringName const&, Vector<Variant> const&, unsigned int>::call (this=0x6409750, p_object=0x6f9f170, p_args=0x7fffd7eb8ef0, p_arg_count=3, r_error=...) at core/method_bind.gen.inc:4285
#13 0x00000000046157f9 in Object::call (this=0x6f9f170, p_method=..., p_args=0x7fffd7eb8ef0, p_argcount=3, r_error=...)
    at core/object.cpp:921
#14 0x00000000046d28f5 in Variant::call_ptr (this=0x7fffd7ebaa60, p_method=..., p_args=0x7fffd7eb8ef0, p_argcount=3, r_ret=0x0, 
    r_error=...) at core/variant_call.cpp:1112
#15 0x00000000018ea067 in GDScriptFunction::call (this=0x67f0d70, p_instance=0x7260fa0, p_args=0x7fffd7ebad60, p_argcount=1, 
    r_err=..., p_state=0x0) at modules/gdscript/gdscript_function.cpp:1081
#16 0x0000000001883b04 in GDScriptInstance::call (this=0x7260fa0, p_method=..., p_args=0x7fffd7ebad60, p_argcount=1, r_error=...)
    at modules/gdscript/gdscript.cpp:1173
#17 0x000000000461563f in Object::call (this=0x6f9f170, p_method=..., p_args=0x7fffd7ebad60, p_argcount=1, r_error=...)
    at core/object.cpp:900
#18 0x000000000492bc25 in _Thread::_start_func (ud=0x70e3f00) at core/bind/core_bind.cpp:2660
#19 0x000000000242b95c in ThreadPosix::thread_callback (userdata=0x725f4f0) at drivers/unix/thread_posix.cpp:74
#20 0x00007ffff7a164cf in start_thread () from /usr/lib/libpthread.so.0
#21 0x00007ffff75f42d3 in clone () from /usr/lib/libc.so.6
```
```
(gdb) bt
#0  0x000000000462513a in CowData<VMap<Object::Signal::Target, Object::Signal::Slot>::Pair>::get_m (this=0x7fffcc000f60, p_index=1)
    at ./core/cowdata.h:145
#1  0x0000000004622129 in VMap<Object::Signal::Target, Object::Signal::Slot>::operator[] (this=0x7fffcc000f60, p_key=...)
    at ./core/vmap.h:202
#2  0x000000000461a406 in Object::connect (this=0x6f9e950, p_signal=..., p_to_object=0x7fffcc000b90, p_to_method=..., p_binds=..., 
    p_flags=0) at core/object.cpp:1485
#3  0x0000000004630e8f in MethodBind5R<Object, Error, StringName const&, Object*, StringName const&, Vector<Variant> const&, unsigned int>::call (this=0x6409750, p_object=0x6f9e950, p_args=0x7fffd7eb8ef0, p_arg_count=3, r_error=...) at core/method_bind.gen.inc:4285
#4  0x00000000046157f9 in Object::call (this=0x6f9e950, p_method=..., p_args=0x7fffd7eb8ef0, p_argcount=3, r_error=...)
    at core/object.cpp:921
#5  0x00000000046d28f5 in Variant::call_ptr (this=0x7fffd7ebaa60, p_method=..., p_args=0x7fffd7eb8ef0, p_argcount=3, r_ret=0x0, 
    r_error=...) at core/variant_call.cpp:1112
#6  0x00000000018ea067 in GDScriptFunction::call (this=0x67f0560, p_instance=0x7260480, p_args=0x7fffd7ebad60, p_argcount=1, 
    r_err=..., p_state=0x0) at modules/gdscript/gdscript_function.cpp:1081
#7  0x0000000001883b04 in GDScriptInstance::call (this=0x7260480, p_method=..., p_args=0x7fffd7ebad60, p_argcount=1, r_error=...)
    at modules/gdscript/gdscript.cpp:1173
#8  0x000000000461563f in Object::call (this=0x6f9e950, p_method=..., p_args=0x7fffd7ebad60, p_argcount=1, r_error=...)
    at core/object.cpp:900
#9  0x000000000492bc25 in _Thread::_start_func (ud=0x70e3610) at core/bind/core_bind.cpp:2660
#10 0x000000000242b95c in ThreadPosix::thread_callback (userdata=0x725e9d0) at drivers/unix/thread_posix.cpp:74
#11 0x00007ffff7a164cf in start_thread () from /usr/lib/libpthread.so.0
#12 0x00007ffff75f42d3 in clone () from /usr/lib/libc.so.6
```

</details>

**Minimal reproduction project:**