-
Suggestion
-
Resolution: Incomplete
-
Not Evaluated
-
None
-
None
-
None
Recently, we've experienced quite a lot of segfaults in our CI piplines with pyside6 and after some debugging, we have a working theory:
Let's say we have a Qt signal and object A is connected to it. Something along the lines of
class Base(QObject): trigger = Signal() class A(QWidget): @Slot() def some_slot(self): print("Slot triggered") a = A() b = Base() b.trigger.connect(a.some_slot) b.trigger.emit()
If object A is marked for deletion (deleteLater), it seems as if there is no guarantee that previously emitted events are blocked. As a result, there is a non-zero risk that the C++ object of the recipient (i.e. object A) does not exist anymore.
This is fine as it can be checked easily with shiboken6.isValid. However, what caught us by surprise that even the python object may get garbage-collected in between. Therefore even a shiboken6.isValid call would segfault as it tries to access an already deleted python object.
We finally managed to provide a fix for it by connecting not to a bound method but instead connecting to a regular function and emitting a weakref to the python object. Upon receiving the event, the dereferencing would allow us to check if the underlying object has already been deleted.
Would you agree that accessing deleted python objects is inherently a risk in pyside6? If the underlying code in pyside6 is indeed not checking whether the object is still alive, maybe one could think about adding something similar to the code base?