diff options
author | Christian Tismer <tismer@stackless.com> | 2020-05-17 14:56:49 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2020-05-18 18:11:25 +0200 |
commit | 8e22b0d5b52f615a9b8ed4d278d103df9f2bd71c (patch) | |
tree | 16a11d7659993e71d4c30824626a985d747850b9 | |
parent | c82ec2bcbdf4db8fc83fefaec6377aaf2bb3614b (diff) |
sbkenum: Fix refcounting leak
sbkenum had a wrong deallocator and some other errors.
Found while developing pickling on enums.
At the same time, a wrong Python 3.8 condition was removed.
There are currently no additional bugs in Python 2.7, 3.7 and 3.8.
Change-Id: I4abccf3b84a3738bba7781ea3dfd00e98ae63ea1
Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r-- | sources/pyside2/libpyside/pysideweakref.cpp | 5 | ||||
-rw-r--r-- | sources/pyside2/tests/QtCore/qenum_test.py | 17 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkenum.cpp | 23 |
3 files changed, 29 insertions, 16 deletions
diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index 84b390e96..cd90634bd 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -98,11 +98,6 @@ PyObject *create(PyObject *obj, PySideWeakRefFunction func, void *userData) PySideCallableObject *callable = PyObject_New(PySideCallableObject, type); if (!callable || PyErr_Occurred()) return 0; - if (!PepRuntime_38_flag) { - // PYSIDE-939: Handling references correctly. - // Workaround for Python issue 35810; no longer necessary in Python 3.8 - Py_INCREF(type); - } PyObject *weak = PyWeakref_NewRef(obj, reinterpret_cast<PyObject *>(callable)); if (!weak || PyErr_Occurred()) diff --git a/sources/pyside2/tests/QtCore/qenum_test.py b/sources/pyside2/tests/QtCore/qenum_test.py index ed58f4f20..1edb8981a 100644 --- a/sources/pyside2/tests/QtCore/qenum_test.py +++ b/sources/pyside2/tests/QtCore/qenum_test.py @@ -30,6 +30,7 @@ '''Test cases for QEnum and QFlags''' +import gc import os import sys import pickle @@ -75,6 +76,22 @@ class TestEnum(unittest.TestCase): with self.assertRaises(TypeError): a = k*2.0 + @unittest.skipUnless(getattr(sys, "getobjects", None), "requires debug build") + def testEnumNew_NoLeak(self): + gc.collect() + total = sys.gettotalrefcount() + for idx in range(1000): + ret = Qt.Key(42) + gc.collect() + delta = sys.gettotalrefcount() - total + print("delta total refcount =", delta) + if abs(delta) >= 10: + all = sys.getobjects(0) + all.sort(key=lambda x: sys.getrefcount(x), reverse=True) + for ob in all[:10]: + print(sys.getrefcount(ob), ob) + self.assertTrue(abs(delta) < 10) + class TestQFlags(unittest.TestCase): def testToItn(self): diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 5b9718738..36f2f48f9 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -107,16 +107,18 @@ static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *) if (!self) return nullptr; self->ob_value = itemValue; - PyObject *item = Shiboken::Enum::getEnumItemFromValue(type, itemValue); - if (item) { - self->ob_name = SbkEnumObject_name(item, nullptr); - Py_XDECREF(item); - } else { - self->ob_name = nullptr; - } + Shiboken::AutoDecRef item(Shiboken::Enum::getEnumItemFromValue(type, itemValue)); + self->ob_name = item.object() ? SbkEnumObject_name(item, nullptr) : nullptr; return reinterpret_cast<PyObject *>(self); } +void enum_object_dealloc(PyObject *ob) +{ + auto self = reinterpret_cast<SbkEnumObject *>(ob); + Py_XDECREF(self->ob_name); + Sbk_object_dealloc(ob); +} + static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) { PyObject *valA = a; PyObject *valB = b; @@ -448,7 +450,7 @@ static bool _init_enum() static void init_enum() { if (!(enum_unpickler || _init_enum())) - Py_FatalError("could not load enum helper functions"); + Py_FatalError("could not load enum pickling helper function"); } static PyMethodDef SbkEnumObject_Methods[] = { @@ -497,7 +499,7 @@ PyObject *getEnumItemFromValue(PyTypeObject *enumType, long itemValue) while (PyDict_Next(values, &pos, &key, &value)) { auto *obj = reinterpret_cast<SbkEnumObject *>(value); if (obj->ob_value == itemValue) { - Py_INCREF(obj); + Py_INCREF(value); return value; } } @@ -644,7 +646,7 @@ static PyType_Slot SbkNewType_slots[] = { {Py_nb_index, (void *)enum_int}, {Py_tp_richcompare, (void *)enum_richcompare}, {Py_tp_hash, (void *)enum_hash}, - {Py_tp_dealloc, (void *)Sbk_object_dealloc}, + {Py_tp_dealloc, (void *)enum_object_dealloc}, {0, nullptr} }; static PyType_Spec SbkNewType_spec = { @@ -735,7 +737,6 @@ newTypeWithName(const char *name, newspec->slots = newslots; auto *type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(newspec)); Py_TYPE(type) = SbkEnumType_TypeF(); - Py_INCREF(Py_TYPE(type)); auto *enumType = reinterpret_cast<SbkEnumType *>(type); PepType_SETP(enumType)->cppName = cppName; |