diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-06-25 15:05:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-25 15:05:06 (GMT) |
commit | 86e49a5026ab9f746b87daae2aca81c845b4a5f4 (patch) | |
tree | 15cfa47acaec2014213c64a0cad8e2c22c566519 /Modules | |
parent | 14943829a8dfacdf5fc1ef78bb155c0e2ec874a4 (diff) | |
download | cpython-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.c | 22 |
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 }; |