Skip to content

Commit 2a54acf

Browse files
authored
gh-116946: fully implement GC protocol for zlib objects (#138290)
1 parent 6f1dd95 commit 2a54acf

File tree

1 file changed

+57
-19
lines changed

1 file changed

+57
-19
lines changed

Modules/zlibmodule.c

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,9 @@ static compobject *
273273
newcompobject(PyTypeObject *type)
274274
{
275275
compobject *self;
276-
self = PyObject_New(compobject, type);
276+
assert(type != NULL);
277+
assert(type->tp_alloc != NULL);
278+
self = _compobject_CAST(type->tp_alloc(type, 0));
277279
if (self == NULL)
278280
return NULL;
279281
self->eof = 0;
@@ -716,33 +718,41 @@ zlib_decompressobj_impl(PyObject *module, int wbits, PyObject *zdict)
716718
}
717719

718720
static void
719-
Dealloc(compobject *self)
721+
compobject_dealloc_impl(PyObject *op, int (*dealloc)(z_streamp))
720722
{
721-
PyTypeObject *type = Py_TYPE(self);
723+
PyTypeObject *type = Py_TYPE(op);
724+
PyObject_GC_UnTrack(op);
725+
compobject *self = _compobject_CAST(op);
726+
if (self->is_initialised) {
727+
(void)dealloc(&self->zst);
728+
}
722729
PyThread_free_lock(self->lock);
723730
Py_XDECREF(self->unused_data);
724731
Py_XDECREF(self->unconsumed_tail);
725732
Py_XDECREF(self->zdict);
726-
PyObject_Free(self);
733+
type->tp_free(self);
727734
Py_DECREF(type);
728735
}
729736

737+
static int
738+
compobject_traverse(PyObject *op, visitproc visit, void *arg)
739+
{
740+
compobject *self = _compobject_CAST(op);
741+
Py_VISIT(Py_TYPE(op));
742+
Py_VISIT(self->zdict);
743+
return 0;
744+
}
745+
730746
static void
731747
Comp_dealloc(PyObject *op)
732748
{
733-
compobject *self = _compobject_CAST(op);
734-
if (self->is_initialised)
735-
(void)deflateEnd(&self->zst);
736-
Dealloc(self);
749+
compobject_dealloc_impl(op, &deflateEnd);
737750
}
738751

739752
static void
740753
Decomp_dealloc(PyObject *op)
741754
{
742-
compobject *self = _compobject_CAST(op);
743-
if (self->is_initialised)
744-
(void)inflateEnd(&self->zst);
745-
Dealloc(self);
755+
compobject_dealloc_impl(op, &inflateEnd);
746756
}
747757

748758
/*[clinic input]
@@ -1368,6 +1378,8 @@ typedef struct {
13681378
char needs_input;
13691379
} ZlibDecompressor;
13701380

1381+
#define ZlibDecompressor_CAST(op) ((ZlibDecompressor *)(op))
1382+
13711383
/*[clinic input]
13721384
class zlib._ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType"
13731385
[clinic start generated code]*/
@@ -1376,19 +1388,29 @@ class zlib._ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType"
13761388
static void
13771389
ZlibDecompressor_dealloc(PyObject *op)
13781390
{
1379-
ZlibDecompressor *self = (ZlibDecompressor*)op;
1380-
PyObject *type = (PyObject *)Py_TYPE(self);
1391+
PyTypeObject *type = Py_TYPE(op);
1392+
PyObject_GC_UnTrack(op);
1393+
ZlibDecompressor *self = ZlibDecompressor_CAST(op);
13811394
PyThread_free_lock(self->lock);
13821395
if (self->is_initialised) {
13831396
inflateEnd(&self->zst);
13841397
}
13851398
PyMem_Free(self->input_buffer);
13861399
Py_CLEAR(self->unused_data);
13871400
Py_CLEAR(self->zdict);
1388-
PyObject_Free(self);
1401+
type->tp_free(self);
13891402
Py_DECREF(type);
13901403
}
13911404

1405+
static int
1406+
ZlibDecompressor_traverse(PyObject *op, visitproc visit, void *arg)
1407+
{
1408+
ZlibDecompressor *self = ZlibDecompressor_CAST(op);
1409+
Py_VISIT(Py_TYPE(op));
1410+
Py_VISIT(self->zdict);
1411+
return 0;
1412+
}
1413+
13921414
static int
13931415
set_inflate_zdict_ZlibDecompressor(zlibstate *state, ZlibDecompressor *self)
13941416
{
@@ -1731,8 +1753,9 @@ static PyObject *
17311753
zlib__ZlibDecompressor_impl(PyTypeObject *type, int wbits, PyObject *zdict)
17321754
/*[clinic end generated code: output=1065607df0d33baa input=9ebad0be6de226e2]*/
17331755
{
1756+
assert(type != NULL && type->tp_alloc != NULL);
17341757
zlibstate *state = PyType_GetModuleState(type);
1735-
ZlibDecompressor *self = PyObject_New(ZlibDecompressor, type);
1758+
ZlibDecompressor *self = ZlibDecompressor_CAST(type->tp_alloc(type, 0));
17361759
if (self == NULL) {
17371760
return NULL;
17381761
}
@@ -2015,19 +2038,25 @@ static PyMethodDef zlib_methods[] =
20152038

20162039
static PyType_Slot Comptype_slots[] = {
20172040
{Py_tp_dealloc, Comp_dealloc},
2041+
{Py_tp_traverse, compobject_traverse},
20182042
{Py_tp_methods, comp_methods},
20192043
{0, 0},
20202044
};
20212045

20222046
static PyType_Spec Comptype_spec = {
20232047
.name = "zlib.Compress",
20242048
.basicsize = sizeof(compobject),
2025-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
2049+
.flags = (
2050+
Py_TPFLAGS_DEFAULT
2051+
| Py_TPFLAGS_DISALLOW_INSTANTIATION
2052+
| Py_TPFLAGS_HAVE_GC
2053+
),
20262054
.slots= Comptype_slots,
20272055
};
20282056

20292057
static PyType_Slot Decomptype_slots[] = {
20302058
{Py_tp_dealloc, Decomp_dealloc},
2059+
{Py_tp_traverse, compobject_traverse},
20312060
{Py_tp_methods, Decomp_methods},
20322061
{Py_tp_members, Decomp_members},
20332062
{0, 0},
@@ -2036,12 +2065,17 @@ static PyType_Slot Decomptype_slots[] = {
20362065
static PyType_Spec Decomptype_spec = {
20372066
.name = "zlib.Decompress",
20382067
.basicsize = sizeof(compobject),
2039-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
2068+
.flags = (
2069+
Py_TPFLAGS_DEFAULT
2070+
| Py_TPFLAGS_DISALLOW_INSTANTIATION
2071+
| Py_TPFLAGS_HAVE_GC
2072+
),
20402073
.slots = Decomptype_slots,
20412074
};
20422075

20432076
static PyType_Slot ZlibDecompressor_type_slots[] = {
20442077
{Py_tp_dealloc, ZlibDecompressor_dealloc},
2078+
{Py_tp_traverse, ZlibDecompressor_traverse},
20452079
{Py_tp_members, ZlibDecompressor_members},
20462080
{Py_tp_new, zlib__ZlibDecompressor},
20472081
{Py_tp_doc, (char *)zlib__ZlibDecompressor__doc__},
@@ -2056,7 +2090,11 @@ static PyType_Spec ZlibDecompressor_type_spec = {
20562090
// ZlibDecompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
20572091
// which prevents to create a subclass.
20582092
// So calling PyType_GetModuleState() in this file is always safe.
2059-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
2093+
.flags = (
2094+
Py_TPFLAGS_DEFAULT
2095+
| Py_TPFLAGS_IMMUTABLETYPE
2096+
| Py_TPFLAGS_HAVE_GC
2097+
),
20602098
.slots = ZlibDecompressor_type_slots,
20612099
};
20622100

0 commit comments

Comments
 (0)