8000 gh-119127: Fix _functools.Placeholder singleton (#124601) · python/cpython@257a20a · GitHub
[go: up one dir, main page]

Skip to content

Commit 257a20a

Browse files
authored
gh-119127: Fix _functools.Placeholder singleton (#124601)
* The module state now stores a strong reference to the Placeholder singleton. * Use a regular dealloc function. * Add Py_TPFLAGS_HAVE_GC flag and a traverse function to help the GC to collect the type when a _functools extension is unloaded.
1 parent abe5f79 commit 257a20a

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

Modules/_functoolsmodule.c

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ typedef struct _functools_state {
2626
/* this object is used delimit args and keywords in the cache keys */
2727
PyObject *kwd_mark;
2828
PyTypeObject *placeholder_type;
29-
PyObject *placeholder;
29+
PyObject *placeholder; // strong reference (singleton)
3030
PyTypeObject *partial_type;
3131
PyTypeObject *keyobject_type;
3232
PyTypeObject *lru_list_elem_type;
@@ -76,13 +76,12 @@ static PyMethodDef placeholder_methods[] = {
7676
};
7777

7878
static void
79-
placeholder_dealloc(PyObject* placeholder)
79+
placeholder_dealloc(PyObject* self)
8080
{
81-
/* This should never get called, but we also don't want to SEGV if
82-
* we accidentally decref Placeholder out of existence. Instead,
83-
* since Placeholder is an immortal object, re-set the reference count.
84-
*/
85-
_Py_SetImmortal(placeholder);
81+
PyObject_GC_UnTrack(self);
82+
PyTypeObject *tp = Py_TYPE(self);
83+
tp->tp_free((PyObject*)self);
84+
Py_DECREF(tp);
8685
}
8786

8887
static PyObject *
@@ -93,10 +92,26 @@ placeholder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
9392
return NULL;
9493
}
9594
_functools_state *state = get_functools_state_by_type(type);
95+
if (state->placeholder != NULL) {
96+
return Py_NewRef(state->placeholder);
97+
}
98+
99+
PyObject *placeholder = PyType_GenericNew(type, NULL, NULL);
100+
if (placeholder == NULL) {
101+
return NULL;
102+
}
103+
96104
if (state->placeholder == NULL) {
97-
state->placeholder = PyType_GenericNew(type, NULL, NULL);
105+
state->placeholder = Py_NewRef(placeholder);
98106
}
99-
return state->placeholder;
107+
return placeholder;
108+
}
109+
110+
static int
111+
placeholder_traverse(PyObject *self, visitproc visit, void *arg)
112+
{
113+
Py_VISIT(Py_TYPE(self));
114+
return 0;
100115
}
101116

102117
static PyType_Slot placeholder_type_slots[] = {
@@ -105,13 +120,14 @@ static PyType_Slot placeholder_type_slots[] = {
105120
{Py_tp_doc, (void *)placeholder_doc},
106121
{Py_tp_methods, placeholder_methods},
107122
{Py_tp_new, placeholder_new},
123+
{Py_tp_traverse, placeholder_traverse},
108124
{0, 0}
109125
};
110126

111127
static PyType_Spec placeholder_type_spec = {
112128
.name = "functools._PlaceholderType",
113129
.basicsize = sizeof(placeholderobject),
114-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
130+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC,
115131
.slots = placeholder_type_slots
116132
};
117133

@@ -1717,13 +1733,17 @@ _functools_exec(PyObject *module)
17171733
if (PyModule_AddType(module, state->placeholder_type) < 0) {
17181734
return -1;
17191735
}
1720-
state->placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
1721-
if (state->placeholder == NULL) {
1736+
1737+
PyObject *placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
1738+
if (placeholder == NULL) {
17221739
return -1;
17231740
}
1724-
if (PyModule_AddObject(module, "Placeholder", state->placeholder) < 0) {
1741+
if (PyModule_AddObjectRef(module, "Placeholder", placeholder) < 0) {
1742+
Py_DECREF(placeholder);
17251743
return -1;
17261744
}
1745+
Py_DECREF(placeholder);
1746+
17271747
state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
17281748
&partial_type_spec, NULL);
17291749
if (state->partial_type == NULL) {
@@ -1769,6 +1789,7 @@ _functools_traverse(PyObject *module, visitproc visit, void *arg)
17691789
_functools_state *state = get_functools_state(module);
17701790
Py_VISIT(state->kwd_mark);
17711791
Py_VISIT(state->placeholder_type);
1792+
Py_VISIT(state->placeholder);
17721793
Py_VISIT(state->partial_type);
17731794
Py_VISIT(state->keyobject_type);
17741795
Py_VISIT(state->lru_list_elem_type);
@@ -1781,6 +1802,7 @@ _functools_clear(PyObject *module)
17811802
_functools_state *state = get_functools_state(module);
17821803
Py_CLEAR(state->kwd_mark);
17831804
Py_CLEAR(state->placeholder_type);
1805+
Py_CLEAR(state->placeholder);
17841806
Py_CLEAR(state->partial_type);
17851807
Py_CLEAR(state->keyobject_type);
17861808
Py_CLEAR(state->lru_list_elem_type);

0 commit comments

Comments
 (0)
0