summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2022-06-25 15:05:06 (GMT)
committerGitHub <noreply@github.com>2022-06-25 15:05:06 (GMT)
commit86e49a5026ab9f746b87daae2aca81c845b4a5f4 (patch)
tree15cfa47acaec2014213c64a0cad8e2c22c566519 /Modules
parent14943829a8dfacdf5fc1ef78bb155c0e2ec874a4 (diff)
downloadcpython-86e49a5026ab9f746b87daae2aca81c845b4a5f4.zip
cpython-86e49a5026ab9f746b87daae2aca81c845b4a5f4.tar.gz
cpython-86e49a5026ab9f746b87daae2aca81c845b4a5f4.tar.bz2
[3.10] gh-94207: Fix struct module leak (GH-94239) (GH-94266)
* gh-94207: Fix struct module leak (GH-94239) Make _struct.Struct a GC type This fixes a memory leak in the _struct module, where as soon as a Struct object is stored in the cache, there's a cycle from the _struct module to the cache to Struct objects to the Struct type back to the module. If _struct.Struct is not gc-tracked, that cycle is never collected. This PR makes _struct.Struct GC-tracked, and adds a regression test. (cherry picked from commit 6b865349aae47b90f9ef0b98f3fe3720c2f05601) Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_struct.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 30ad9f2..79806ea 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1495,10 +1495,26 @@ Struct___init___impl(PyStructObject *self, PyObject *format)
return ret;
}
+static int
+s_clear(PyStructObject *s)
+{
+ Py_CLEAR(s->s_format);
+ return 0;
+}
+
+static int
+s_traverse(PyStructObject *s, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(s));
+ Py_VISIT(s->s_format);
+ return 0;
+}
+
static void
s_dealloc(PyStructObject *s)
{
PyTypeObject *tp = Py_TYPE(s);
+ PyObject_GC_UnTrack(s);
if (s->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)s);
if (s->s_codes != NULL) {
@@ -2079,13 +2095,15 @@ static PyType_Slot PyStructType_slots[] = {
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_setattro, PyObject_GenericSetAttr},
{Py_tp_doc, (void*)s__doc__},
+ {Py_tp_traverse, s_traverse},
+ {Py_tp_clear, s_clear},
{Py_tp_methods, s_methods},
{Py_tp_members, s_members},
{Py_tp_getset, s_getsetlist},
{Py_tp_init, Struct___init__},
{Py_tp_alloc, PyType_GenericAlloc},
{Py_tp_new, s_new},
- {Py_tp_free, PyObject_Del},
+ {Py_tp_free, PyObject_GC_Del},
{0, 0},
};
@@ -2093,7 +2111,7 @@ static PyType_Spec PyStructType_spec = {
"_struct.Struct",
sizeof(PyStructObject),
0,
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
PyStructType_slots
};