aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2020-05-17 14:56:49 +0200
committerChristian Tismer <tismer@stackless.com>2020-05-18 18:11:25 +0200
commit8e22b0d5b52f615a9b8ed4d278d103df9f2bd71c (patch)
tree16a11d7659993e71d4c30824626a985d747850b9
parentc82ec2bcbdf4db8fc83fefaec6377aaf2bb3614b (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.cpp5
-rw-r--r--sources/pyside2/tests/QtCore/qenum_test.py17
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.cpp23
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;