Browse Source

Merge pull request #35423 from Faless/fix/object_emit_free

Make sure we know when deleting an emitting object
Rémi Verschelde 5 years ago
parent
commit
409de53e72
2 changed files with 10 additions and 9 deletions
  1. 8 7
      core/object.cpp
  2. 2 2
      core/object.h

+ 8 - 7
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);
 			MessageQueue::get_singleton()->push_call(target->get_instance_id(), c.method, args, argc, true);
 		} else {
 		} else {
 			Variant::CallError ce;
 			Variant::CallError ce;
-			s->lock++;
+			_emitting = true;
 			target->call(c.method, args, argc, ce);
 			target->call(c.method, args, argc, ce);
-			s->lock--;
+			_emitting = false;
 
 
 			if (ce.error != Variant::CallError::CALL_OK) {
 			if (ce.error != Variant::CallError::CALL_OK) {
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
@@ -1920,6 +1920,7 @@ Object::Object() {
 	_instance_id = ObjectDB::add_instance(this);
 	_instance_id = ObjectDB::add_instance(this);
 	_can_translate = true;
 	_can_translate = true;
 	_is_queued_for_deletion = false;
 	_is_queued_for_deletion = false;
+	_emitting = false;
 	instance_binding_count = 0;
 	instance_binding_count = 0;
 	memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
 	memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
 	script_instance = NULL;
 	script_instance = NULL;
@@ -1942,15 +1943,15 @@ Object::~Object() {
 
 
 	const StringName *S = NULL;
 	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))) {
 	while ((S = signal_map.next(NULL))) {
 
 
 		Signal *s = &signal_map[*S];
 		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
 		//brute force disconnect for performance
 		int slot_count = s->slot_map.size();
 		int slot_count = s->slot_map.size();
 		const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array();
 		const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array();

+ 2 - 2
core/object.h

@@ -465,8 +465,7 @@ private:
 
 
 		MethodInfo user;
 		MethodInfo user;
 		VMap<Target, Slot> slot_map;
 		VMap<Target, Slot> slot_map;
-		int lock;
-		Signal() { lock = 0; }
+		Signal() {}
 	};
 	};
 
 
 	HashMap<StringName, Signal> signal_map;
 	HashMap<StringName, Signal> signal_map;
@@ -481,6 +480,7 @@ private:
 	bool _predelete();
 	bool _predelete();
 	void _postinitialize();
 	void _postinitialize();
 	bool _can_translate;
 	bool _can_translate;
+	bool _emitting;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	bool _edited;
 	bool _edited;
 	uint32_t _edited_version;
 	uint32_t _edited_version;