aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside6/libpyside/pysidesignal.cpp21
-rw-r--r--sources/pyside6/libpyside/pysidesignal.h1
-rw-r--r--sources/pyside6/tests/QtCore/destroysignal_test.py27
3 files changed, 48 insertions, 1 deletions
diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp
index 5df42261c..cdc3042c0 100644
--- a/sources/pyside6/libpyside/pysidesignal.cpp
+++ b/sources/pyside6/libpyside/pysidesignal.cpp
@@ -6,6 +6,7 @@
#include "pysidesignal_p.h"
#include "pysideutils.h"
#include "pysidestaticstrings.h"
+#include "pysideweakref.h"
#include "signalmanager.h"
#include <shiboken.h>
@@ -342,6 +343,7 @@ static void signalInstanceFree(void *vself)
}
delete dataPvt;
self->d = nullptr;
+ self->deleted = true;
Py_TYPE(pySelf)->tp_base->tp_free(self);
}
@@ -550,6 +552,13 @@ static PyObject *signalInstanceEmit(PyObject *self, PyObject *args)
{
PySideSignalInstance *source = reinterpret_cast<PySideSignalInstance *>(self);
+ // PYSIDE-2201: Check if the object has vanished meanwhile.
+ // Tried to revive it without exception, but this gives problems.
+ if (source->deleted) {
+ PyErr_Format(PyExc_RuntimeError, "The SignalInstance object was already deleted");
+ return nullptr;
+ }
+
Shiboken::AutoDecRef pyArgs(PyList_New(0));
int numArgsGiven = PySequence_Fast_GET_SIZE(args);
int numArgsInSignature = argCountInSignature(source->d->signature);
@@ -932,9 +941,16 @@ static void appendSignature(PySideSignal *self, const SignalSignature &signature
self->data->signatures.append({signature.m_parameterTypes, signature.m_attributes});
}
+static void sourceGone(void *data)
+{
+ auto *self = reinterpret_cast<PySideSignalInstance *>(data);
+ self->deleted = true;
+}
+
static void instanceInitialize(PySideSignalInstance *self, PyObject *name, PySideSignal *signal, PyObject *source, int index)
{
self->d = new PySideSignalInstancePrivate;
+ self->deleted = false;
PySideSignalInstancePrivate *selfPvt = self->d;
selfPvt->next = nullptr;
if (signal->data->signalName.isEmpty())
@@ -950,6 +966,10 @@ static void instanceInitialize(PySideSignalInstance *self, PyObject *name, PySid
selfPvt->homonymousMethod = signal->homonymousMethod;
Py_INCREF(selfPvt->homonymousMethod);
}
+ // PYSIDE-2201: We have no reference to source. Let's take a weakref to get
+ // notified when source gets deleted.
+ PySide::WeakRef::create(source, sourceGone, self);
+
index++;
if (index < signal->data->signatures.size()) {
@@ -1009,6 +1029,7 @@ PySideSignalInstance *newObjectFromMethod(PyObject *source, const QList<QMetaMet
previous->d->next = item;
item->d = new PySideSignalInstancePrivate;
+ item->deleted = false;
PySideSignalInstancePrivate *selfPvt = item->d;
selfPvt->source = source;
Py_INCREF(selfPvt->source); // PYSIDE-79: an INCREF is missing.
diff --git a/sources/pyside6/libpyside/pysidesignal.h b/sources/pyside6/libpyside/pysidesignal.h
index c38371d81..3b82e6c58 100644
--- a/sources/pyside6/libpyside/pysidesignal.h
+++ b/sources/pyside6/libpyside/pysidesignal.h
@@ -30,6 +30,7 @@ extern "C"
{
PyObject_HEAD
PySideSignalInstancePrivate *d;
+ bool deleted;
};
}; // extern "C"
diff --git a/sources/pyside6/tests/QtCore/destroysignal_test.py b/sources/pyside6/tests/QtCore/destroysignal_test.py
index 34aaded9e..f1d7cfec1 100644
--- a/sources/pyside6/tests/QtCore/destroysignal_test.py
+++ b/sources/pyside6/tests/QtCore/destroysignal_test.py
@@ -11,7 +11,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from init_paths import init_test_paths
init_test_paths(False)
-from PySide6.QtCore import QTimer, QObject
+from PySide6.QtCore import QTimer, QObject, Signal
class TestDestroySignal(unittest.TestCase):
@@ -43,6 +43,31 @@ class TestDestroySignal(unittest.TestCase):
self.assertTrue(self._destroyed)
+class Foo(QObject):
+ s = Signal(int)
+
+ def __init__(self):
+ QObject.__init__(self)
+ sys.stderr.write(f"__init__ {id(self):x}\n")
+
+ def __del__(self):
+ sys.stderr.write(f"__del__ {id(self):x}\n")
+
+ def send(self, i):
+ self.s.emit(i)
+
+
+# PYSIDE-2201: This crashed until we introduced a weak reference.
+class TestDestroyNoConnect(unittest.TestCase):
+
+ def testSignalDestroyedMissingReference(self):
+ # This works since it has one reference more to Foo
+ Foo().send(43)
+ # This crashed because we have no reference in the signal.
+ with self.assertRaises(RuntimeError):
+ Foo().s.emit(44)
+
+
if __name__ == '__main__':
unittest.main()