summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2024-09-26 14:50:38 (GMT)
committerGitHub <noreply@github.com>2024-09-26 14:50:38 (GMT)
commit257a20a81764fcc17bcde9c0cec57fbc53a4adc7 (patch)
tree32592f63994993b8ff275ef497bbbda9d8af5b9a
parentabe5f799e6ce1d177f79554f1b84d348b6141045 (diff)
downloadcpython-257a20a81764fcc17bcde9c0cec57fbc53a4adc7.zip
cpython-257a20a81764fcc17bcde9c0cec57fbc53a4adc7.tar.gz
cpython-257a20a81764fcc17bcde9c0cec57fbc53a4adc7.tar.bz2
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.
-rw-r--r--Modules/_functoolsmodule.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 2b3bd7c..31cf7bc 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -26,7 +26,7 @@ typedef struct _functools_state {
/* this object is used delimit args and keywords in the cache keys */
PyObject *kwd_mark;
PyTypeObject *placeholder_type;
- PyObject *placeholder;
+ PyObject *placeholder; // strong reference (singleton)
PyTypeObject *partial_type;
PyTypeObject *keyobject_type;
PyTypeObject *lru_list_elem_type;
@@ -76,13 +76,12 @@ static PyMethodDef placeholder_methods[] = {
};
static void
-placeholder_dealloc(PyObject* placeholder)
+placeholder_dealloc(PyObject* self)
{
- /* This should never get called, but we also don't want to SEGV if
- * we accidentally decref Placeholder out of existence. Instead,
- * since Placeholder is an immortal object, re-set the reference count.
- */
- _Py_SetImmortal(placeholder);
+ PyObject_GC_UnTrack(self);
+ PyTypeObject *tp = Py_TYPE(self);
+ tp->tp_free((PyObject*)self);
+ Py_DECREF(tp);
}
static PyObject *
@@ -93,10 +92,26 @@ placeholder_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
return NULL;
}
_functools_state *state = get_functools_state_by_type(type);
+ if (state->placeholder != NULL) {
+ return Py_NewRef(state->placeholder);
+ }
+
+ PyObject *placeholder = PyType_GenericNew(type, NULL, NULL);
+ if (placeholder == NULL) {
+ return NULL;
+ }
+
if (state->placeholder == NULL) {
- state->placeholder = PyType_GenericNew(type, NULL, NULL);
+ state->placeholder = Py_NewRef(placeholder);
}
- return state->placeholder;
+ return placeholder;
+}
+
+static int
+placeholder_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
}
static PyType_Slot placeholder_type_slots[] = {
@@ -105,13 +120,14 @@ static PyType_Slot placeholder_type_slots[] = {
{Py_tp_doc, (void *)placeholder_doc},
{Py_tp_methods, placeholder_methods},
{Py_tp_new, placeholder_new},
+ {Py_tp_traverse, placeholder_traverse},
{0, 0}
};
static PyType_Spec placeholder_type_spec = {
.name = "functools._PlaceholderType",
.basicsize = sizeof(placeholderobject),
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC,
.slots = placeholder_type_slots
};
@@ -1717,13 +1733,17 @@ _functools_exec(PyObject *module)
if (PyModule_AddType(module, state->placeholder_type) < 0) {
return -1;
}
- state->placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
- if (state->placeholder == NULL) {
+
+ PyObject *placeholder = PyObject_CallNoArgs((PyObject *)state->placeholder_type);
+ if (placeholder == NULL) {
return -1;
}
- if (PyModule_AddObject(module, "Placeholder", state->placeholder) < 0) {
+ if (PyModule_AddObjectRef(module, "Placeholder", placeholder) < 0) {
+ Py_DECREF(placeholder);
return -1;
}
+ Py_DECREF(placeholder);
+
state->partial_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
&partial_type_spec, NULL);
if (state->partial_type == NULL) {
@@ -1769,6 +1789,7 @@ _functools_traverse(PyObject *module, visitproc visit, void *arg)
_functools_state *state = get_functools_state(module);
Py_VISIT(state->kwd_mark);
Py_VISIT(state->placeholder_type);
+ Py_VISIT(state->placeholder);
Py_VISIT(state->partial_type);
Py_VISIT(state->keyobject_type);
Py_VISIT(state->lru_list_elem_type);
@@ -1781,6 +1802,7 @@ _functools_clear(PyObject *module)
_functools_state *state = get_functools_state(module);
Py_CLEAR(state->kwd_mark);
Py_CLEAR(state->placeholder_type);
+ Py_CLEAR(state->placeholder);
Py_CLEAR(state->partial_type);
Py_CLEAR(state->keyobject_type);
Py_CLEAR(state->lru_list_elem_type);