From: Victor Stinner Date: Thu, 8 Mar 2012 23:44:13 +0000 (+0100) Subject: Issue #14211: _PyObject_GenericSetAttrWithDict() keeps a strong reference to X-Git-Tag: v3.3.0a2~258 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2d01dc00bc4ca3eb0cf1cc1ee44859a4eaf165d9;p=python Issue #14211: _PyObject_GenericSetAttrWithDict() keeps a strong reference to the descriptor because it may be destroyed before being used, destroyed during the update of the dict for example. --- diff --git a/Lib/test/crashers/borrowed_ref_1.py b/Lib/test/crashers/borrowed_ref_1.py deleted file mode 100644 index b82f4644bf..0000000000 --- a/Lib/test/crashers/borrowed_ref_1.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -_PyType_Lookup() returns a borrowed reference. -This attacks the call in dictobject.c. -""" - -class A(object): - pass - -class B(object): - def __del__(self): - print('hi') - del D.__missing__ - -class D(dict): - class __missing__: - def __init__(self, *args): - pass - - -d = D() -a = A() -a.cycle = a -a.other = B() -del a - -prev = None -while 1: - d[5] - prev = (prev,) diff --git a/Objects/object.c b/Objects/object.c index 70d320ca35..08ad68f05a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1074,7 +1074,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) f = descr->ob_type->tp_descr_get; if (f != NULL && PyDescr_IsData(descr)) { res = f(descr, obj, (PyObject *)obj->ob_type); - Py_DECREF(descr); goto done; } } @@ -1105,7 +1104,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) res = PyDict_GetItem(dict, name); if (res != NULL) { Py_INCREF(res); - Py_XDECREF(descr); Py_DECREF(dict); goto done; } @@ -1114,13 +1112,12 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) if (f != NULL) { res = f(descr, obj, (PyObject *)Py_TYPE(obj)); - Py_DECREF(descr); goto done; } if (descr != NULL) { res = descr; - /* descr was already increfed above */ + descr = NULL; goto done; } @@ -1128,6 +1125,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) "'%.50s' object has no attribute '%U'", tp->tp_name, name); done: + Py_XDECREF(descr); Py_DECREF(name); return res; } @@ -1163,6 +1161,8 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, } descr = _PyType_Lookup(tp, name); + Py_XINCREF(descr); + f = NULL; if (descr != NULL) { f = descr->ob_type->tp_descr_set; @@ -1212,6 +1212,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, "'%.50s' object attribute '%U' is read-only", tp->tp_name, name); done: + Py_XDECREF(descr); Py_DECREF(name); return res; }