diff options
author | John Ehresman <jpe@wingware.com> | 2012-07-18 14:17:49 -0400 |
---|---|---|
committer | Marcelo Lira <marcelo.lira@openbossa.org> | 2012-07-31 22:24:28 +0200 |
commit | ea6575953822193df672e5fe132f3aa9298e0536 (patch) | |
tree | 1e6dbcbc79b5aa7b751a7e04617ec004b7ef19a6 | |
parent | 1cea6192fa32fee29ae64cdc2bda1414e6a443bd (diff) |
During signal emission don't get return type after callback
The callback can disconnect the slot, causing the C++ object for
the connection to be deleted. Accessing the return type would then
read already freed memory.
Change-Id: Ib33fa806978793bcac42167dd45f1e59829a3104
Reviewed-by: Marcelo Lira <marcelo.lira@openbossa.org>
-rw-r--r-- | libpyside/signalmanager.cpp | 25 | ||||
-rw-r--r-- | tests/signals/disconnect_test.py | 25 |
2 files changed, 39 insertions, 11 deletions
diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp index 81ce14dc..d9184eba 100644 --- a/libpyside/signalmanager.cpp +++ b/libpyside/signalmanager.cpp @@ -452,22 +452,25 @@ int SignalManager::callPythonMetaMethod(const QMetaMethod& method, void** args, pyArguments = parseArguments(method.parameterTypes(), args); if (pyArguments) { + Shiboken::Conversions::SpecificConverter* retConverter = NULL; + const char* returnType = method.typeName(); + if (returnType && std::strcmp("", returnType)) { + retConverter = new Shiboken::Conversions::SpecificConverter(returnType); + if (!retConverter || !*retConverter) { + PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s' to call Python meta method.", returnType); + PyErr_Print(); + return -1; + } + } + Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, pyArguments)); if (!isShortCuit && pyArguments) Py_DECREF(pyArguments); - if (!retval.isNull() && retval != Py_None && !PyErr_Occurred()) { - const char* returnType = method.typeName(); - if (returnType && std::strcmp("", returnType)) { - Shiboken::Conversions::SpecificConverter converter(returnType); - if (converter) - converter.toCpp(retval, args[0]); - else - PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s' to call Python meta method.", returnType); - - } - } + if (!retval.isNull() && retval != Py_None && !PyErr_Occurred() && retConverter) + retConverter->toCpp(retval, args[0]); + delete retConverter; } if (PyErr_Occurred()) diff --git a/tests/signals/disconnect_test.py b/tests/signals/disconnect_test.py index cceaf873..d2e7217a 100644 --- a/tests/signals/disconnect_test.py +++ b/tests/signals/disconnect_test.py @@ -1,5 +1,7 @@ import unittest from PySide.QtCore import * +from testbinding import TestObject + class Foo(QObject): bar = Signal() @@ -28,5 +30,28 @@ class TestDisconnect(unittest.TestCase): self.assertFalse(self.called1) self.assertFalse(self.called2) + def testDuringCallback(self): + """ Test to see if the C++ object for a connection is accessed after the + method returns. This causes a segfault if the memory that was used by the + C++ object has been reused. """ + + self.called = False + obj = TestObject(0) + def callback(): + obj.signalWithDefaultValue.disconnect(callback) + + # Connect more callbacks to try to overwrite memory + for i in range(1000): + obj.signalWithDefaultValue.connect(lambda: None) + + self.called = True + + # A non-None return value is needed + return True + obj.signalWithDefaultValue.connect(callback) + obj.signalWithDefaultValue.emit() + self.assert_(self.called) + + if __name__ == '__main__': unittest.main() |