Skip to content

Commit cbf890f

Browse files
msmolensjcfr
authored andcommitted
Fix PythonQtSignalReceiver crash during cleanup
This commit fixes a crash during PythonQt::cleanup(). While destroying the PythonQtPrivate instance, any remaining PythonQtSignalReceivers that are kept alive only by their parent object will be destroyed. The crash occurs when PythonQtSignalReceiver's destructor calls back into PythonQtPrivate::removeSignalEmitter() when the PythonQtPrivate instance is mostly destroyed. Includes test case that crashes without the fix.
1 parent d1b0cac commit cbf890f

File tree

3 files changed

+22
-5
lines changed

3 files changed

+22
-5
lines changed

src/PythonQt.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName)
246246
void PythonQt::cleanup()
247247
{
248248
if (_self) {
249+
// Remove signal handlers in advance, since destroying them calls back into
250+
// PythonQt::priv()->removeSignalEmitter()
251+
_self->removeSignalHandlers();
252+
249253
delete _self;
250254
_self = NULL;
251255
}

tests/PythonQtTestCleanup.cpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@ void PythonQtTestCleanup::cleanup()
2626
{
2727
// Finalize and cleanup after each test
2828

29-
PythonQtObjectPtr main = PythonQt::self()->getMainModule();
30-
PythonQt::self()->removeVariable(main, "obj");
31-
delete _helper;
32-
_helper = NULL;
33-
3429
if (Py_IsInitialized()) {
3530
Py_Finalize();
3631
}
3732

3833
PythonQt::cleanup();
34+
35+
delete _helper;
36+
_helper = NULL;
3937
}
4038

4139
void PythonQtTestCleanup::testQtEnum()
@@ -61,6 +59,19 @@ void PythonQtTestCleanup::testCallQtMethodInDel()
6159
));
6260
}
6361

62+
void PythonQtTestCleanup::testSignalReceiverCleanup()
63+
{
64+
PythonQtObjectPtr main = PythonQt::self()->getMainModule();
65+
66+
// Test that PythonQtSignalReceiver is cleaned up properly,
67+
// i.e. PythonQt::cleanup() doesn't segfault
68+
main.evalScript(
69+
"import PythonQt.QtCore\n" \
70+
"timer = PythonQt.QtCore.QTimer(obj)\n" \
71+
"timer.connect('destroyed()', obj.onDestroyed)\n" \
72+
);
73+
}
74+
6475
bool PythonQtTestCleanupHelper::runScript(const char* script)
6576
{
6677
_passed = false;

tests/PythonQtTestCleanup.h

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ private Q_SLOTS:
1919

2020
void testQtEnum();
2121
void testCallQtMethodInDel();
22+
void testSignalReceiverCleanup();
2223

2324
private:
2425
PythonQtTestCleanupHelper* _helper;
@@ -37,6 +38,7 @@ class PythonQtTestCleanupHelper : public QObject
3738

3839
public Q_SLOTS:
3940
void setPassed() { _passed = true; }
41+
void onDestroyed(QObject *) { }
4042

4143
private:
4244
bool _passed;

0 commit comments

Comments
 (0)