Commit 2d01dc00 authored by Victor Stinner's avatar Victor Stinner

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.
parent d74782b0
"""
_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,)
...@@ -1074,7 +1074,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) ...@@ -1074,7 +1074,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict)
f = descr->ob_type->tp_descr_get; f = descr->ob_type->tp_descr_get;
if (f != NULL && PyDescr_IsData(descr)) { if (f != NULL && PyDescr_IsData(descr)) {
res = f(descr, obj, (PyObject *)obj->ob_type); res = f(descr, obj, (PyObject *)obj->ob_type);
Py_DECREF(descr);
goto done; goto done;
} }
} }
...@@ -1105,7 +1104,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) ...@@ -1105,7 +1104,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict)
res = PyDict_GetItem(dict, name); res = PyDict_GetItem(dict, name);
if (res != NULL) { if (res != NULL) {
Py_INCREF(res); Py_INCREF(res);
Py_XDECREF(descr);
Py_DECREF(dict); Py_DECREF(dict);
goto done; goto done;
} }
...@@ -1114,13 +1112,12 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) ...@@ -1114,13 +1112,12 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict)
if (f != NULL) { if (f != NULL) {
res = f(descr, obj, (PyObject *)Py_TYPE(obj)); res = f(descr, obj, (PyObject *)Py_TYPE(obj));
Py_DECREF(descr);
goto done; goto done;
} }
if (descr != NULL) { if (descr != NULL) {
res = descr; res = descr;
/* descr was already increfed above */ descr = NULL;
goto done; goto done;
} }
...@@ -1128,6 +1125,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) ...@@ -1128,6 +1125,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict)
"'%.50s' object has no attribute '%U'", "'%.50s' object has no attribute '%U'",
tp->tp_name, name); tp->tp_name, name);
done: done:
Py_XDECREF(descr);
Py_DECREF(name); Py_DECREF(name);
return res; return res;
} }
...@@ -1163,6 +1161,8 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, ...@@ -1163,6 +1161,8 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
} }
descr = _PyType_Lookup(tp, name); descr = _PyType_Lookup(tp, name);
Py_XINCREF(descr);
f = NULL; f = NULL;
if (descr != NULL) { if (descr != NULL) {
f = descr->ob_type->tp_descr_set; f = descr->ob_type->tp_descr_set;
...@@ -1212,6 +1212,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, ...@@ -1212,6 +1212,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
"'%.50s' object attribute '%U' is read-only", "'%.50s' object attribute '%U' is read-only",
tp->tp_name, name); tp->tp_name, name);
done: done:
Py_XDECREF(descr);
Py_DECREF(name); Py_DECREF(name);
return res; return res;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment