Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 400d8ee

Browse files
committed
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.
1 parent 547eb42 commit 400d8ee

1 file changed

Lines changed: 45 additions & 8 deletions

File tree

Objects/funcobject.c

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -590,10 +590,29 @@ typedef struct {
590590
static void
591591
cm_dealloc(classmethod *cm)
592592
{
593+
_PyObject_GC_UNTRACK((PyObject *)cm);
593594
Py_XDECREF(cm->cm_callable);
594595
cm->ob_type->tp_free((PyObject *)cm);
595596
}
596597

598+
static int
599+
cm_traverse(classmethod *cm, visitproc visit, void *arg)
600+
{
601+
if (!cm->cm_callable)
602+
return 0;
603+
return visit(cm->cm_callable, arg);
604+
}
605+
606+
static int
607+
cm_clear(classmethod *cm)
608+
{
609+
Py_XDECREF(cm->cm_callable);
610+
cm->cm_callable = NULL;
611+
612+
return 0;
613+
}
614+
615+
597616
static PyObject *
598617
cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
599618
{
@@ -665,10 +684,10 @@ PyTypeObject PyClassMethod_Type = {
665684
PyObject_GenericGetAttr, /* tp_getattro */
666685
0, /* tp_setattro */
667686
0, /* tp_as_buffer */
668-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
687+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
669688
classmethod_doc, /* tp_doc */
670-
0, /* tp_traverse */
671-
0, /* tp_clear */
689+
(traverseproc)cm_traverse, /* tp_traverse */
690+
(inquiry)cm_clear, /* tp_clear */
672691
0, /* tp_richcompare */
673692
0, /* tp_weaklistoffset */
674693
0, /* tp_iter */
@@ -684,7 +703,7 @@ PyTypeObject PyClassMethod_Type = {
684703
cm_init, /* tp_init */
685704
PyType_GenericAlloc, /* tp_alloc */
686705
PyType_GenericNew, /* tp_new */
687-
PyObject_Del, /* tp_free */
706+
PyObject_GC_Del, /* tp_free */
688707
};
689708

690709
PyObject *
@@ -724,10 +743,28 @@ typedef struct {
724743
static void
725744
sm_dealloc(staticmethod *sm)
726745
{
746+
_PyObject_GC_UNTRACK((PyObject *)sm);
727747
Py_XDECREF(sm->sm_callable);
728748
sm->ob_type->tp_free((PyObject *)sm);
729749
}
730750

751+
static int
752+
sm_traverse(staticmethod *sm, visitproc visit, void *arg)
753+
{
754+
if (!sm->sm_callable)
755+
return 0;
756+
return visit(sm->sm_callable, arg);
757+
}
758+
759+
static int
760+
sm_clear(staticmethod *sm)
761+
{
762+
Py_XDECREF(sm->sm_callable);
763+
sm->sm_callable = NULL;
764+
765+
return 0;
766+
}
767+
731768
static PyObject *
732769
sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
733770
{
@@ -794,10 +831,10 @@ PyTypeObject PyStaticMethod_Type = {
794831
PyObject_GenericGetAttr, /* tp_getattro */
795832
0, /* tp_setattro */
796833
0, /* tp_as_buffer */
797-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
834+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
798835
staticmethod_doc, /* tp_doc */
799-
0, /* tp_traverse */
800-
0, /* tp_clear */
836+
(traverseproc)sm_traverse, /* tp_traverse */
837+
(inquiry)sm_clear, /* tp_clear */
801838
0, /* tp_richcompare */
802839
0, /* tp_weaklistoffset */
803840
0, /* tp_iter */
@@ -813,7 +850,7 @@ PyTypeObject PyStaticMethod_Type = {
813850
sm_init, /* tp_init */
814851
PyType_GenericAlloc, /* tp_alloc */
815852
PyType_GenericNew, /* tp_new */
816-
PyObject_Del, /* tp_free */
853+
PyObject_GC_Del, /* tp_free */
817854
};
818855

819856
PyObject *

0 commit comments

Comments
 (0)