Skip to content

Commit 8d1037f

Browse files
committed
gh-135228: Break reference cycle between class and descriptors
1 parent 4615164 commit 8d1037f

3 files changed

Lines changed: 17 additions & 9 deletions

File tree

Lib/inspect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1698,7 +1698,7 @@ def _shadowed_dict_from_weakref_mro_tuple(*weakref_mro):
16981698
class_dict = dunder_dict['__dict__']
16991699
if not (type(class_dict) is types.GetSetDescriptorType and
17001700
class_dict.__name__ == "__dict__" and
1701-
class_dict.__objclass__ is entry):
1701+
(class_dict.__objclass__ is entry or class_dict.__objclass__ is object)):
17021702
return class_dict
17031703
return _sentinel
17041704

Objects/descrobject.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,11 @@ getset_get(PyObject *self, PyObject *obj, PyObject *type)
190190
if (descr_check((PyDescrObject *)descr, obj) < 0) {
191191
return NULL;
192192
}
193-
if (descr->d_getset->get != NULL)
193+
if (descr->d_getset->get != NULL) {
194+
void *closure = descr->d_getset->closure == (void *)1 ? NULL : descr->d_getset->closure;
194195
return descr_get_trampoline_call(
195-
descr->d_getset->get, obj, descr->d_getset->closure);
196+
descr->d_getset->get, obj, closure);
197+
}
196198
PyErr_Format(PyExc_AttributeError,
197199
"attribute '%V' of '%.100s' objects is not readable",
198200
descr_name((PyDescrObject *)descr), "?",
@@ -247,9 +249,9 @@ getset_set(PyObject *self, PyObject *obj, PyObject *value)
247249
return -1;
248250
}
249251
if (descr->d_getset->set != NULL) {
252+
void *closure = descr->d_getset->closure == (void *)1 ? NULL : descr->d_getset->closure;
250253
return descr_set_trampoline_call(
251-
descr->d_getset->set, obj, value,
252-
descr->d_getset->closure);
254+
descr->d_getset->set, obj, value, closure);
253255
}
254256
PyErr_Format(PyExc_AttributeError,
255257
"attribute '%V' of '%.100s' objects is not writable",
@@ -1004,10 +1006,16 @@ PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)
10041006
{
10051007
PyGetSetDescrObject *descr;
10061008

1009+
bool should_adjust_d_type = (getset->closure == (void *)1);
1010+
10071011
descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
10081012
type, getset->name);
10091013
if (descr != NULL)
10101014
descr->d_getset = getset;
1015+
1016+
if (should_adjust_d_type) {
1017+
Py_SETREF(descr->d_common.d_type, &PyBaseObject_Type);
1018+
}
10111019
return (PyObject *)descr;
10121020
}
10131021

Objects/typeobject.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4031,21 +4031,21 @@ subtype_getweakref(PyObject *obj, void *context)
40314031

40324032
static PyGetSetDef subtype_getsets_full[] = {
40334033
{"__dict__", subtype_dict, subtype_setdict,
4034-
PyDoc_STR("dictionary for instance variables")},
4034+
PyDoc_STR("dictionary for instance variables"), (void *)1},
40354035
{"__weakref__", subtype_getweakref, NULL,
4036-
PyDoc_STR("list of weak references to the object")},
4036+
PyDoc_STR("list of weak references to the object"), (void *)1},
40374037
{0}
40384038
};
40394039

40404040
static PyGetSetDef subtype_getsets_dict_only[] = {
40414041
{"__dict__", subtype_dict, subtype_setdict,
4042-
PyDoc_STR("dictionary for instance variables")},
4042+
PyDoc_STR("dictionary for instance variables"), (void *)1},
40434043
{0}
40444044
};
40454045

40464046
static PyGetSetDef subtype_getsets_weakref_only[] = {
40474047
{"__weakref__", subtype_getweakref, NULL,
4048-
PyDoc_STR("list of weak references to the object")},
4048+
PyDoc_STR("list of weak references to the object"), (void *)1},
40494049
{0}
40504050
};
40514051

0 commit comments

Comments
 (0)