summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabio Alessandrelli <fabio.alessandrelli@gmail.com>2020-01-22 01:45:06 +0100
committerFabio Alessandrelli <fabio.alessandrelli@gmail.com>2020-01-22 14:08:16 +0100
commit41f59ecfca6ddea1eb7b023aaea75e80e3c30c5c (patch)
tree716d27c5f2df28ed505e2ed43036ed745c4c42cc
parent5127afa812f80c02e6f9fada854d46482daafca4 (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.cpp15
-rw-r--r--core/object.h4
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;