diff options
author | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2020-01-22 01:45:06 +0100 |
---|---|---|
committer | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2020-01-22 14:08:16 +0100 |
commit | 41f59ecfca6ddea1eb7b023aaea75e80e3c30c5c (patch) | |
tree | 716d27c5f2df28ed505e2ed43036ed745c4c42cc | |
parent | 5127afa812f80c02e6f9fada854d46482daafca4 (diff) |
Make sure we know when deleting an emitting object
We used a lock signals in the signal_map while emitting, because it was
not allowed to disconnect them while being emitted.
We used that lock to check if we where deleting an object during signal
emission.
Now that we allow to disconnect signals while they are being emitted, if
an object first disconnects, then gets deleted we can't know that a
signal was being emitted during the destructor.
This commit adds a new `_emitting` boolean member to Object to be set
while emitting and checked in the destructor, while removing the old
signal lock which is now unused.
-rw-r--r-- | core/object.cpp | 15 | ||||
-rw-r--r-- | core/object.h | 4 |
2 files changed, 10 insertions, 9 deletions
diff --git a/core/object.cpp b/core/object.cpp index 21666a334c..21a3b2cc6c 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1213,9 +1213,9 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int MessageQueue::get_singleton()->push_call(target->get_instance_id(), c.method, args, argc, true); } else { Variant::CallError ce; - s->lock++; + _emitting = true; target->call(c.method, args, argc, ce); - s->lock--; + _emitting = false; if (ce.error != Variant::CallError::CALL_OK) { #ifdef DEBUG_ENABLED @@ -1920,6 +1920,7 @@ Object::Object() { _instance_id = ObjectDB::add_instance(this); _can_translate = true; _is_queued_for_deletion = false; + _emitting = false; instance_binding_count = 0; memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); script_instance = NULL; @@ -1942,15 +1943,15 @@ Object::~Object() { const StringName *S = NULL; + if (_emitting) { + //@todo this may need to actually reach the debugger prioritarily somehow because it may crash before + ERR_PRINTS("Object " + to_string() + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes."); + } + while ((S = signal_map.next(NULL))) { Signal *s = &signal_map[*S]; - if (s->lock > 0) { - //@todo this may need to actually reach the debugger prioritarily somehow because it may crash before - ERR_PRINTS("Object was freed or unreferenced while signal '" + String(*S) + "' is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes."); - } - //brute force disconnect for performance int slot_count = s->slot_map.size(); const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array(); diff --git a/core/object.h b/core/object.h index ad1865da7b..865c155764 100644 --- a/core/object.h +++ b/core/object.h @@ -465,8 +465,7 @@ private: MethodInfo user; VMap<Target, Slot> slot_map; - int lock; - Signal() { lock = 0; } + Signal() {} }; HashMap<StringName, Signal> signal_map; @@ -481,6 +480,7 @@ private: bool _predelete(); void _postinitialize(); bool _can_translate; + bool _emitting; #ifdef TOOLS_ENABLED bool _edited; uint32_t _edited_version; |