From 7b90fd37378853ed47153463298db66a3a98ecac Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 6 Dec 2022 12:22:09 +0100 Subject: Use a proper @pyqtSlot for FilenamePrompt In bleeding tests, we started to get a segfault on the second test in tests/unit/mainwindow/test_prompt.py, with a stacktrace like: Thread 1 "python" received signal SIGSEGV, Segmentation fault. 0x00007ffff7b55912 in _PyFunction_Vectorcall (func=, stack=0x7fffd74656a8, nargsf=, kwnames=0x0) at Objects/call.c:341 341 if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) { (gdb) bt #0 0x00007ffff7b55912 in _PyFunction_Vectorcall (func=, stack=0x7fffd74656a8, nargsf=, kwnames=0x0) at Objects/call.c:341 #1 0x00007ffff4e0b3f1 in PyQtSlot::call(_object*, _object*) const (this=0x555556c759c0, args=('/tmp/pytest-of-florian/pytest-70/test_simple_completion_1_next_0/test',), callable=) at ../../qpy/QtCore/qpycore_pyqtslot.cpp:247 #2 PyQtSlot::invoke(void**, _object*, void*, bool) const (this=0x555556c759c0, qargs=, qargs@entry=0x7fffffff86c0, self=, self@entry=0x0, result=result@entry=0x0, no_receiver_check=) at ../../qpy/QtCore/qpycore_pyqtslot.cpp:159 #3 0x00007ffff4e12213 in PyQtSlot::invoke(void**, bool) const (no_receiver_check=, qargs=0x7fffffff86c0, this=) at ../../qpy/QtCore/qpycore_pyqtslot.cpp:78 #4 PyQtSlotProxy::unislot(void**) (qargs=0x7fffffff86c0, this=0x555557193e20) at ../../qpy/QtCore/qpycore_pyqtslotproxy.cpp:205 #5 PyQtSlotProxy::unislot(void**) (qargs=0x7fffffff86c0, this=0x555557193e20) at ../../qpy/QtCore/qpycore_pyqtslotproxy.cpp:186 #6 PyQtSlotProxy::qt_metacall(QMetaObject::Call, int, void**) (this=0x555557193e20, _c=, _id=0, _a=0x7fffffff86c0) at ../../qpy/QtCore/qpycore_pyqtslotproxy.cpp:170 #7 0x00007ffff48bd91d in doActivate(QObject*, int, void**) (sender=0x555556b3d680, signal_index=28, argv=0x7fffffff86c0) at kernel/qobject.cpp:3945 #8 0x00007fffeff96aca in QFileSystemModel::directoryLoaded(QString const&) (this=, _t1=) at .moc/moc_qfilesystemmodel.cpp:272 #9 0x00007ffff48b0be0 in QObject::event(QEvent*) (this=this@entry=0x555556b3d680, e=e@entry=0x7fff0c004af0) at kernel/qobject.cpp:1347 #10 0x00007fffeff962ab in QFileSystemModel::event(QEvent*) (this=this@entry=0x555556b3d680, event=event@entry=0x7fff0c004af0) at dialogs/qfilesystemmodel.cpp:1748 #11 0x00007ffff070995c in sipQFileSystemModel::event(QEvent*) (this=0x555556b3d680, a0=0x7fff0c004af0) at /usr/src/debug/pyqt5/PyQt5-5.15.7/build/QtWidgets/sipQtWidgetsQFileSystemModel.cpp:376 [...] #23 0x00007ffff4da94ce in meth_QCoreApplication_processEvents(PyObject*, PyObject*, PyObject*) (sipArgs=, sipKwds=0x0) at /usr/src/debug/pyqt5/PyQt5-5.15.7/build/QtCore/sipQtCoreQCoreApplication.cpp:590 [...] from pytest-qt in Python: Current thread 0x00007fb366207740 (most recent call first): File ".../pytestqt/plugin.py", line 209 in _process_events File ".../pytestqt/plugin.py", line 171 in pytest_runtest_setup [...] File ".../pytest/src/_pytest/runner.py", line 115 in pytest_runtest_protocol [...] File ".../pytest/src/_pytest/main.py", line 317 in pytest_cmdline_main [...] Introduced by this change in pytest, which now deletes the temporary directory after the test by default: https://github.com/pytest-dev/pytest/pull/10517 It sounds like something odd like the directory removal causing (Py)Qt to call the lambda, but the underlying Python object already being gone or something along those lines. With a proper Qt slot (@pyqtSlot), PyQt seems to do the right thing, so let's just use that instead... --- qutebrowser/mainwindow/prompt.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py index 5d3bced59..c5acaabda 100644 --- a/qutebrowser/mainwindow/prompt.py +++ b/qutebrowser/mainwindow/prompt.py @@ -760,9 +760,21 @@ class FilenamePrompt(_BasePrompt): self._file_view.setColumnHidden(col, True) # Nothing selected initially self._file_view.setCurrentIndex(QModelIndex()) - # The model needs to be sorted so we get the correct first/last index - self._file_model.directoryLoaded.connect( - lambda: self._file_model.sort(0)) + + self._file_model.directoryLoaded.connect(self.on_directory_loaded) + + @pyqtSlot() + def on_directory_loaded(self): + """Sort the model after a directory gets loaded. + + The model needs to be sorted so we get the correct first/last index. + + NOTE: This needs to be a proper @pystSlot() function, and not a lambda. + Otherwise, PyQt seems to fail to disconnect it immediately after the + object gets destroyed, and we get segfaults when deleting the directory + in unit tests. + """ + self._file_model.sort(0) def accept(self, value=None, save=False): self._check_save_support(save) -- cgit v1.2.3-54-g00ecf