Skip to content

Commit eb8ab04

Browse files
miss-islingtonErlend Egeberg Aasland
and
Erlend Egeberg Aasland
authored
bpo-42972: Fully implement GC protocol for functools keywrapper and partial types (GH-26363) (GH-26424)
(cherry picked from commit 8994e9c) Co-authored-by: Erlend Egeberg Aasland <[email protected]>
1 parent 35be1f3 commit eb8ab04

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

Modules/_functoolsmodule.c

+37-22
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,37 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
147147
return (PyObject *)pto;
148148
}
149149

150+
static int
151+
partial_clear(partialobject *pto)
152+
{
153+
Py_CLEAR(pto->fn);
154+
Py_CLEAR(pto->args);
155+
Py_CLEAR(pto->kw);
156+
Py_CLEAR(pto->dict);
157+
return 0;
158+
}
159+
160+
static int
161+
partial_traverse(partialobject *pto, visitproc visit, void *arg)
162+
{
163+
Py_VISIT(Py_TYPE(pto));
164+
Py_VISIT(pto->fn);
165+
Py_VISIT(pto->args);
166+
Py_VISIT(pto->kw);
167+
Py_VISIT(pto->dict);
168+
return 0;
169+
}
170+
150171
static void
151172
partial_dealloc(partialobject *pto)
152173
{
153174
PyTypeObject *tp = Py_TYPE(pto);
154175
/* bpo-31095: UnTrack is needed before calling any callbacks */
155176
PyObject_GC_UnTrack(pto);
156-
if (pto->weakreflist != NULL)
177+
if (pto->weakreflist != NULL) {
157178
PyObject_ClearWeakRefs((PyObject *) pto);
158-
Py_XDECREF(pto->fn);
159-
Py_XDECREF(pto->args);
160-
Py_XDECREF(pto->kw);
161-
Py_XDECREF(pto->dict);
179+
}
180+
(void)partial_clear(pto);
162181
tp->tp_free(pto);
163182
Py_DECREF(tp);
164183
}
@@ -307,16 +326,6 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
307326
return res;
308327
}
309328

310-
static int
311-
partial_traverse(partialobject *pto, visitproc visit, void *arg)
312-
{
313-
Py_VISIT(pto->fn);
314-
Py_VISIT(pto->args);
315-
Py_VISIT(pto->kw);
316-
Py_VISIT(pto->dict);
317-
return 0;
318-
}
319-
320329
PyDoc_STRVAR(partial_doc,
321330
"partial(func, *args, **keywords) - new function with partial application\n\
322331
of the given arguments and keywords.\n");
@@ -469,6 +478,7 @@ static PyType_Slot partial_type_slots[] = {
469478
{Py_tp_setattro, PyObject_GenericSetAttr},
470479
{Py_tp_doc, (void *)partial_doc},
471480
{Py_tp_traverse, partial_traverse},
481+
{Py_tp_clear, partial_clear},
472482
{Py_tp_methods, partial_methods},
473483
{Py_tp_members, partial_memberlist},
474484
{Py_tp_getset, partial_getsetlist},
@@ -506,14 +516,16 @@ static void
506516
keyobject_dealloc(keyobject *ko)
507517
{
508518
PyTypeObject *tp = Py_TYPE(ko);
509-
keyobject_clear(ko);
510-
PyObject_Free(ko);
519+
PyObject_GC_UnTrack(ko);
520+
(void)keyobject_clear(ko);
521+
tp->tp_free(ko);
511522
Py_DECREF(tp);
512523
}
513524

514525
static int
515526
keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
516527
{
528+
Py_VISIT(Py_TYPE(ko));
517529
Py_VISIT(ko->cmp);
518530
Py_VISIT(ko->object);
519531
return 0;
@@ -546,7 +558,8 @@ static PyType_Slot keyobject_type_slots[] = {
546558
static PyType_Spec keyobject_type_spec = {
547559
.name = "functools.KeyWrapper",
548560
.basicsize = sizeof(keyobject),
549-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
561+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
562+
Py_TPFLAGS_HAVE_GC),
550563
.slots = keyobject_type_slots
551564
};
552565

@@ -560,14 +573,15 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
560573
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
561574
return NULL;
562575

563-
result = PyObject_New(keyobject, Py_TYPE(ko));
576+
result = PyObject_GC_New(keyobject, Py_TYPE(ko));
564577
if (result == NULL) {
565578
return NULL;
566579
}
567580
Py_INCREF(ko->cmp);
568581
result->cmp = ko->cmp;
569582
Py_INCREF(object);
570583
result->object = object;
584+
PyObject_GC_Track(result);
571585
return (PyObject *)result;
572586
}
573587

@@ -621,12 +635,13 @@ functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
621635
return NULL;
622636

623637
state = get_functools_state(self);
624-
object = PyObject_New(keyobject, state->keyobject_type);
638+
object = PyObject_GC_New(keyobject, state->keyobject_type);
625639
if (!object)
626640
return NULL;
627641
Py_INCREF(cmp);
628642
object->cmp = cmp;
629643
object->object = NULL;
644+
PyObject_GC_Track(object);
630645
return (PyObject *)object;
631646
}
632647

@@ -754,7 +769,7 @@ lru_list_elem_dealloc(lru_list_elem *link)
754769
PyTypeObject *tp = Py_TYPE(link);
755770
Py_XDECREF(link->key);
756771
Py_XDECREF(link->result);
757-
PyObject_Free(link);
772+
tp->tp_free(link);
758773
Py_DECREF(tp);
759774
}
760775

@@ -1260,7 +1275,7 @@ lru_cache_dealloc(lru_cache_object *obj)
12601275
PyObject_ClearWeakRefs((PyObject*)obj);
12611276
}
12621277

1263-
lru_cache_tp_clear(obj);
1278+
(void)lru_cache_tp_clear(obj);
12641279
tp->tp_free(obj);
12651280
Py_DECREF(tp);
12661281
}

0 commit comments

Comments
 (0)