mirror of
https://github.com/python/cpython.git
synced 2025-11-26 21:33:10 +00:00
Make staticmethods and classmethods participate in GC.
If a class was defined inside a function, used a static or class method, and used super() inside the method body, it would be caught in an uncollectable cycle. (Simplified version: The static/class method object would point to a function object with a closure that referred to the class.) Bugfix candidate.
This commit is contained in:
parent
547eb42d75
commit
400d8ee6fa
1 changed files with 45 additions and 8 deletions
|
|
@ -590,10 +590,29 @@ typedef struct {
|
||||||
static void
|
static void
|
||||||
cm_dealloc(classmethod *cm)
|
cm_dealloc(classmethod *cm)
|
||||||
{
|
{
|
||||||
|
_PyObject_GC_UNTRACK((PyObject *)cm);
|
||||||
Py_XDECREF(cm->cm_callable);
|
Py_XDECREF(cm->cm_callable);
|
||||||
cm->ob_type->tp_free((PyObject *)cm);
|
cm->ob_type->tp_free((PyObject *)cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cm_traverse(classmethod *cm, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
if (!cm->cm_callable)
|
||||||
|
return 0;
|
||||||
|
return visit(cm->cm_callable, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cm_clear(classmethod *cm)
|
||||||
|
{
|
||||||
|
Py_XDECREF(cm->cm_callable);
|
||||||
|
cm->cm_callable = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||||
{
|
{
|
||||||
|
|
@ -665,10 +684,10 @@ PyTypeObject PyClassMethod_Type = {
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
|
||||||
classmethod_doc, /* tp_doc */
|
classmethod_doc, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
(traverseproc)cm_traverse, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
(inquiry)cm_clear, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
0, /* tp_iter */
|
0, /* tp_iter */
|
||||||
|
|
@ -684,7 +703,7 @@ PyTypeObject PyClassMethod_Type = {
|
||||||
cm_init, /* tp_init */
|
cm_init, /* tp_init */
|
||||||
PyType_GenericAlloc, /* tp_alloc */
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
PyType_GenericNew, /* tp_new */
|
PyType_GenericNew, /* tp_new */
|
||||||
PyObject_Del, /* tp_free */
|
PyObject_GC_Del, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
|
@ -724,10 +743,28 @@ typedef struct {
|
||||||
static void
|
static void
|
||||||
sm_dealloc(staticmethod *sm)
|
sm_dealloc(staticmethod *sm)
|
||||||
{
|
{
|
||||||
|
_PyObject_GC_UNTRACK((PyObject *)sm);
|
||||||
Py_XDECREF(sm->sm_callable);
|
Py_XDECREF(sm->sm_callable);
|
||||||
sm->ob_type->tp_free((PyObject *)sm);
|
sm->ob_type->tp_free((PyObject *)sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sm_traverse(staticmethod *sm, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
if (!sm->sm_callable)
|
||||||
|
return 0;
|
||||||
|
return visit(sm->sm_callable, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sm_clear(staticmethod *sm)
|
||||||
|
{
|
||||||
|
Py_XDECREF(sm->sm_callable);
|
||||||
|
sm->sm_callable = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||||
{
|
{
|
||||||
|
|
@ -794,10 +831,10 @@ PyTypeObject PyStaticMethod_Type = {
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
|
||||||
staticmethod_doc, /* tp_doc */
|
staticmethod_doc, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
(traverseproc)sm_traverse, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
(inquiry)sm_clear, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
0, /* tp_iter */
|
0, /* tp_iter */
|
||||||
|
|
@ -813,7 +850,7 @@ PyTypeObject PyStaticMethod_Type = {
|
||||||
sm_init, /* tp_init */
|
sm_init, /* tp_init */
|
||||||
PyType_GenericAlloc, /* tp_alloc */
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
PyType_GenericNew, /* tp_new */
|
PyType_GenericNew, /* tp_new */
|
||||||
PyObject_Del, /* tp_free */
|
PyObject_GC_Del, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue