[Python-checkins] bpo-42972: Fully support GC for pyexpat, unicodedata, and dbm/gdbm heap types (GH-26376)

ncoghlan webhook-mailer at python.org
Thu May 27 03:29:15 EDT 2021


https://github.com/python/cpython/commit/59af59c2dfa52dcd5605185263f266a49ced934c
commit: 59af59c2dfa52dcd5605185263f266a49ced934c
branch: main
author: Erlend Egeberg Aasland <erlend.aasland at innova.no>
committer: ncoghlan <ncoghlan at gmail.com>
date: 2021-05-27T17:29:00+10:00
summary:

bpo-42972: Fully support GC for pyexpat, unicodedata, and dbm/gdbm heap types (GH-26376)

* bpo-42972: pyexpat
* bpo-42972: unicodedata
* bpo-42972: dbm/gdbm

files:
M Modules/_dbmmodule.c
M Modules/_gdbmmodule.c
M Modules/_lsprof.c
M Modules/pyexpat.c
M Modules/unicodedata.c

diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c
index 96d0b0a5cfe6a..2b4d071b3d1ae 100644
--- a/Modules/_dbmmodule.c
+++ b/Modules/_dbmmodule.c
@@ -65,13 +65,14 @@ typedef struct {
 static PyObject *
 newdbmobject(_dbm_state *state, const char *file, int flags, int mode)
 {
-    dbmobject *dp;
-
-    dp = PyObject_New(dbmobject, state->dbm_type);
-    if (dp == NULL)
+    dbmobject *dp = PyObject_GC_New(dbmobject, state->dbm_type);
+    if (dp == NULL) {
         return NULL;
+    }
     dp->di_size = -1;
     dp->flags = flags;
+    PyObject_GC_Track(dp);
+
     /* See issue #19296 */
     if ( (dp->di_dbm = dbm_open((char *)file, flags, mode)) == 0 ) {
         PyErr_SetFromErrnoWithFilename(state->dbm_error, file);
@@ -82,10 +83,17 @@ newdbmobject(_dbm_state *state, const char *file, int flags, int mode)
 }
 
 /* Methods */
+static int
+dbm_traverse(dbmobject *dp, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(dp));
+    return 0;
+}
 
 static void
 dbm_dealloc(dbmobject *dp)
 {
+    PyObject_GC_UnTrack(dp);
     if (dp->di_dbm) {
         dbm_close(dp->di_dbm);
     }
@@ -397,6 +405,7 @@ static PyMethodDef dbm_methods[] = {
 
 static PyType_Slot dbmtype_spec_slots[] = {
     {Py_tp_dealloc, dbm_dealloc},
+    {Py_tp_traverse, dbm_traverse},
     {Py_tp_methods, dbm_methods},
     {Py_sq_contains, dbm_contains},
     {Py_mp_length, dbm_length},
@@ -413,7 +422,8 @@ static PyType_Spec dbmtype_spec = {
     // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
     // which prevents to create a subclass.
     // So calling PyType_GetModuleState() in this file is always safe.
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
+              Py_TPFLAGS_HAVE_GC),
     .slots = dbmtype_spec_slots,
 };
 
diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c
index dc8b8b692c1a3..98bfa6ab99611 100644
--- a/Modules/_gdbmmodule.c
+++ b/Modules/_gdbmmodule.c
@@ -74,12 +74,14 @@ nextkey, reorganize, and sync.");
 static PyObject *
 newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
 {
-    gdbmobject *dp = PyObject_New(gdbmobject, state->gdbm_type);
+    gdbmobject *dp = PyObject_GC_New(gdbmobject, state->gdbm_type);
     if (dp == NULL) {
         return NULL;
     }
     dp->di_size = -1;
     errno = 0;
+    PyObject_GC_Track(dp);
+
     if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
         if (errno != 0) {
             PyErr_SetFromErrnoWithFilename(state->gdbm_error, file);
@@ -94,10 +96,17 @@ newgdbmobject(_gdbm_state *state, const char *file, int flags, int mode)
 }
 
 /* Methods */
+static int
+gdbm_traverse(gdbmobject *dp, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(dp));
+    return 0;
+}
 
 static void
 gdbm_dealloc(gdbmobject *dp)
 {
+    PyObject_GC_UnTrack(dp);
     if (dp->di_dbm) {
         gdbm_close(dp->di_dbm);
     }
@@ -554,6 +563,7 @@ static PyMethodDef gdbm_methods[] = {
 
 static PyType_Slot gdbmtype_spec_slots[] = {
     {Py_tp_dealloc, gdbm_dealloc},
+    {Py_tp_traverse, gdbm_traverse},
     {Py_tp_methods, gdbm_methods},
     {Py_sq_contains, gdbm_contains},
     {Py_mp_length, gdbm_length},
@@ -570,7 +580,8 @@ static PyType_Spec gdbmtype_spec = {
     // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag
     // which prevents to create a subclass.
     // So calling PyType_GetModuleState() in this file is always safe.
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
+              Py_TPFLAGS_HAVE_GC),
     .slots = gdbmtype_spec_slots,
 };
 
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index c32699cb8ad58..a0e6afa844086 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -731,6 +731,13 @@ profiler_clear(ProfilerObject *pObj, PyObject* noarg)
     Py_RETURN_NONE;
 }
 
+static int
+profiler_traverse(ProfilerObject *op, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(op));
+    return 0;
+}
+
 static void
 profiler_dealloc(ProfilerObject *op)
 {
@@ -798,16 +805,14 @@ static PyType_Slot _lsprof_profiler_type_spec_slots[] = {
     {Py_tp_methods, profiler_methods},
     {Py_tp_dealloc, profiler_dealloc},
     {Py_tp_init, profiler_init},
-    {Py_tp_alloc, PyType_GenericAlloc},
-    {Py_tp_new, PyType_GenericNew},
-    {Py_tp_free, PyObject_Del},
+    {Py_tp_traverse, profiler_traverse},
     {0, 0}
 };
 
 static PyType_Spec _lsprof_profiler_type_spec = {
     .name = "_lsprof.Profiler",
     .basicsize = sizeof(ProfilerObject),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
     .slots = _lsprof_profiler_type_spec_slots,
 };
 
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index 7f727a86f5f47..9b04df36f5201 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -1182,19 +1182,34 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
     return (PyObject*)self;
 }
 
+static int
+xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
+{
+    for (int i = 0; handler_info[i].name != NULL; i++) {
+        Py_VISIT(op->handlers[i]);
+    }
+    Py_VISIT(Py_TYPE(op));
+    return 0;
+}
+
+static int
+xmlparse_clear(xmlparseobject *op)
+{
+    clear_handlers(op, 0);
+    Py_CLEAR(op->intern);
+    return 0;
+}
 
 static void
 xmlparse_dealloc(xmlparseobject *self)
 {
-    int i;
     PyObject_GC_UnTrack(self);
     if (self->itself != NULL)
         XML_ParserFree(self->itself);
     self->itself = NULL;
+    (void)xmlparse_clear(self);
 
     if (self->handlers != NULL) {
-        for (i = 0; handler_info[i].name != NULL; i++)
-            Py_CLEAR(self->handlers[i]);
         PyMem_Free(self->handlers);
         self->handlers = NULL;
     }
@@ -1202,7 +1217,6 @@ xmlparse_dealloc(xmlparseobject *self)
         PyMem_Free(self->buffer);
         self->buffer = NULL;
     }
-    Py_XDECREF(self->intern);
     PyTypeObject *tp = Py_TYPE(self);
     PyObject_GC_Del(self);
     Py_DECREF(tp);
@@ -1473,23 +1487,6 @@ static PyGetSetDef xmlparse_getsetlist[] = {
 #undef XMLPARSE_GETTER_DEF
 #undef XMLPARSE_GETTER_SETTER_DEF
 
-static int
-xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
-{
-    int i;
-    for (i = 0; handler_info[i].name != NULL; i++)
-        Py_VISIT(op->handlers[i]);
-    return 0;
-}
-
-static int
-xmlparse_clear(xmlparseobject *op)
-{
-    clear_handlers(op, 0);
-    Py_CLEAR(op->intern);
-    return 0;
-}
-
 PyDoc_STRVAR(Xmlparsetype__doc__, "XML parser");
 
 static PyType_Slot _xml_parse_type_spec_slots[] = {
diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c
index 2e8d199de86ca..a4b8193fbc230 100644
--- a/Modules/unicodedata.c
+++ b/Modules/unicodedata.c
@@ -102,12 +102,13 @@ new_previous_version(PyTypeObject *ucd_type,
                      Py_UCS4 (*normalization)(Py_UCS4))
 {
     PreviousDBVersion *self;
-    self = PyObject_New(PreviousDBVersion, ucd_type);
+    self = PyObject_GC_New(PreviousDBVersion, ucd_type);
     if (self == NULL)
         return NULL;
     self->name = name;
     self->getrecord = getrecord;
     self->normalization = normalization;
+    PyObject_GC_Track(self);
     return (PyObject*)self;
 }
 
@@ -1435,16 +1436,25 @@ static PyMethodDef unicodedata_functions[] = {
     {NULL, NULL}                /* sentinel */
 };
 
+static int
+ucd_traverse(PreviousDBVersion *self, visitproc visit, void *arg)
+{
+    Py_VISIT(Py_TYPE(self));
+    return 0;
+}
+
 static void
 ucd_dealloc(PreviousDBVersion *self)
 {
     PyTypeObject *tp = Py_TYPE(self);
-    PyObject_Free(self);
+    PyObject_GC_UnTrack(self);
+    PyObject_GC_Del(self);
     Py_DECREF(tp);
 }
 
 static PyType_Slot ucd_type_slots[] = {
     {Py_tp_dealloc, ucd_dealloc},
+    {Py_tp_traverse, ucd_traverse},
     {Py_tp_getattro, PyObject_GenericGetAttr},
     {Py_tp_methods, unicodedata_functions},
     {Py_tp_members, DB_members},
@@ -1454,7 +1464,8 @@ static PyType_Slot ucd_type_slots[] = {
 static PyType_Spec ucd_type_spec = {
     .name = "unicodedata.UCD",
     .basicsize = sizeof(PreviousDBVersion),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
+              Py_TPFLAGS_HAVE_GC),
     .slots = ucd_type_slots
 };
 



More information about the Python-checkins mailing list