[PyQt] Segfault when QObject is 'shared' between threads
Ales Erjavec
ales.erjavec324 at gmail.com
Fri Oct 26 11:03:09 BST 2018
Hi,
The following test fails (eventually) with a segmentation fault.
```
from concurrent.futures import ThreadPoolExecutor
from PyQt5.QtCore import Qt, QObject, QCoreApplication
from PyQt5.QtCore import QMetaObject
class TestObject(QObject):
def event(self, event):
return super().event(event)
executor = ThreadPoolExecutor()
app = QCoreApplication([])
def test(parent=None):
obj = TestObject(parent)
def run():
nonlocal obj # capture obj in the run's closure
pass
f = executor.submit(run)
# run the event loop until future's completion
@f.add_done_callback
def quit(f):
QMetaObject.invokeMethod(app, "quit", Qt.QueuedConnection)
app.exec()
obj.deleteLater() # delete the object from the event queue
iter_n = 0
while True:
test(parent=app)
iter_n += 1
if iter_n % 10 == 0:
print("iter:", iter_n)
```
The test object is created in the main thread and is parented. It is
passed in a closure to a thread.
The run function does not even touch it. The only interaction that
should happen is an eventual
Py_DECREF once the worker thread is done. Note that this can happen
after the obj.deleteLater()
is called on the main thread and the test function exists.
I suspect that the problem is double deletion. The event loop picks up
the DeferredDelete event and
starts to delete the object (without the GIL held), at the same time
the closure reference is decrefed
while the state (parent ownership) is inconsistent.
Note that `event` method on TestObject must be overridden in python
for the test to fail.
Tested on:
* macOS 10.11.6, Python 3.5 PyQt 5.9.2, and Python 3.6 PyQt 5.11.3
* KDE Neon (Ubuntu 16.04) Python 3.5 PyQt 5.11.2
More information about the PyQt
mailing list