Skip to content

Commit e8d800e

Browse files
committed
fully implement GC protocol for zlib objects
1 parent 31d3836 commit e8d800e

File tree

1 file changed

+93
-48
lines changed

1 file changed

+93
-48
lines changed

Modules/zlibmodule.c

Lines changed: 93 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -273,29 +273,35 @@ static compobject *
273273
newcompobject(PyTypeObject *type)
274274
{
275275
compobject *self;
276-
self = PyObject_New(compobject, type);
277-
if (self == NULL)
276+
self = PyObject_GC_New(compobject, type);
277+
if (self == NULL) {
278278
return NULL;
279-
self->eof = 0;
280-
self->is_initialised = 0;
281-
self->zdict = NULL;
279+
}
280+
281+
/* Initialize the remaining fields (untouched by PyObject_GC_New()). */
282+
const size_t offset = sizeof(struct { PyObject_HEAD });
283+
memset((char *)self + offset, 0, sizeof(*self) - offset);
284+
282285
self->unused_data = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
283286
if (self->unused_data == NULL) {
284-
Py_DECREF(self);
285-
return NULL;
287+
goto error;
286288
}
287289
self->unconsumed_tail = Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
288290
if (self->unconsumed_tail == NULL) {
289-
Py_DECREF(self);
290-
return NULL;
291+
goto error;
291292
}
292293
self->lock = PyThread_allocate_lock();
293294
if (self->lock == NULL) {
294-
Py_DECREF(self);
295295
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
296-
return NULL;
296+
goto error;
297297
}
298+
299+
PyObject_GC_Track(self);
298300
return self;
301+
302+
error:
303+
Py_DECREF(self);
304+
return NULL;
299305
}
300306

301307
static void*
@@ -716,33 +722,41 @@ zlib_decompressobj_impl(PyObject *module, int wbits, PyObject *zdict)
716722
}
717723

718724
static void
719-
Dealloc(compobject *self)
725+
compobject_dealloc_impl(PyObject *op, int (*dealloc)(z_streamp))
720726
{
721-
PyTypeObject *type = Py_TYPE(self);
727+
PyTypeObject *type = Py_TYPE(op);
728+
PyObject_GC_UnTrack(op);
729+
compobject *self = _compobject_CAST(op);
730+
if (self->is_initialised) {
731+
(void)dealloc(&self->zst);
732+
}
722733
PyThread_free_lock(self->lock);
723734
Py_XDECREF(self->unused_data);
724735
Py_XDECREF(self->unconsumed_tail);
725736
Py_XDECREF(self->zdict);
726-
PyObject_Free(self);
737+
PyObject_GC_Del(self);
727738
Py_DECREF(type);
728739
}
729740

741+
static int
742+
compobject_traverse(PyObject *op, visitproc visit, void *arg)
743+
{
744+
compobject *self = _compobject_CAST(op);
745+
Py_VISIT(Py_TYPE(op));
746+
Py_VISIT(self->zdict);
747+
return 0;
748+
}
749+
730750
static void
731751
Comp_dealloc(PyObject *op)
732752
{
733-
compobject *self = _compobject_CAST(op);
734-
if (self->is_initialised)
735-
(void)deflateEnd(&self->zst);
736-
Dealloc(self);
753+
compobject_dealloc_impl(op, &deflateEnd);
737754
}
738755

739756
static void
740757
Decomp_dealloc(PyObject *op)
741758
{
742-
compobject *self = _compobject_CAST(op);
743-
if (self->is_initialised)
744-
(void)inflateEnd(&self->zst);
745-
Dealloc(self);
759+
compobject_dealloc_impl(op, &inflateEnd);
746760
}
747761

748762
/*[clinic input]
@@ -1115,6 +1129,7 @@ zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls)
11151129
return_value->is_initialised = 1;
11161130

11171131
LEAVE_ZLIB(self);
1132+
assert(PyObject_GC_IsTracked((PyObject *)return_value));
11181133
return (PyObject *)return_value;
11191134

11201135
error:
@@ -1200,6 +1215,7 @@ zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls)
12001215
return_value->is_initialised = 1;
12011216

12021217
LEAVE_ZLIB(self);
1218+
assert(PyObject_GC_IsTracked((PyObject *)return_value));
12031219
return (PyObject *)return_value;
12041220

12051221
error:
@@ -1368,6 +1384,8 @@ typedef struct {
13681384
char needs_input;
13691385
} ZlibDecompressor;
13701386

1387+
#define ZlibDecompressor_CAST(op) ((ZlibDecompressor *)(op))
1388+
13711389
/*[clinic input]
13721390
class zlib._ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType"
13731391
[clinic start generated code]*/
@@ -1376,19 +1394,29 @@ class zlib._ZlibDecompressor "ZlibDecompressor *" "&ZlibDecompressorType"
13761394
static void
13771395
ZlibDecompressor_dealloc(PyObject *op)
13781396
{
1379-
ZlibDecompressor *self = (ZlibDecompressor*)op;
1380-
PyObject *type = (PyObject *)Py_TYPE(self);
1397+
PyTypeObject *type = Py_TYPE(op);
1398+
PyObject_GC_UnTrack(op);
1399+
ZlibDecompressor *self = ZlibDecompressor_CAST(op);
13811400
PyThread_free_lock(self->lock);
13821401
if (self->is_initialised) {
13831402
inflateEnd(&self->zst);
13841403
}
13851404
PyMem_Free(self->input_buffer);
13861405
Py_CLEAR(self->unused_data);
13871406
Py_CLEAR(self->zdict);
1388-
PyObject_Free(self);
1407+
PyObject_GC_Del(self);
13891408
Py_DECREF(type);
13901409
}
13911410

1411+
static int
1412+
ZlibDecompressor_traverse(PyObject *op, visitproc visit, void *arg)
1413+
{
1414+
ZlibDecompressor *self = ZlibDecompressor_CAST(op);
1415+
Py_VISIT(Py_TYPE(op));
1416+
Py_VISIT(self->zdict);
1417+
return 0;
1418+
}
1419+
13921420
static int
13931421
set_inflate_zdict_ZlibDecompressor(zlibstate *state, ZlibDecompressor *self)
13941422
{
@@ -1732,57 +1760,59 @@ zlib__ZlibDecompressor_impl(PyTypeObject *type, int wbits, PyObject *zdict)
17321760
/*[clinic end generated code: output=1065607df0d33baa input=9ebad0be6de226e2]*/
17331761
{
17341762
zlibstate *state = PyType_GetModuleState(type);
1735-
ZlibDecompressor *self = PyObject_New(ZlibDecompressor, type);
1763+
ZlibDecompressor *self = PyObject_GC_New(ZlibDecompressor, type);
17361764
if (self == NULL) {
17371765
return NULL;
17381766
}
1739-
self->eof = 0;
1767+
1768+
/* Initialize the remaining fields (untouched by PyObject_GC_New()). */
1769+
const size_t offset = sizeof(struct { PyObject_HEAD });
1770+
memset((char *)self + offset, 0, sizeof(*self) - offset);
1771+
17401772
self->needs_input = 1;
1741-
self->avail_in_real = 0;
1742-
self->input_buffer = NULL;
1743-
self->input_buffer_size = 0;
17441773
self->zdict = Py_XNewRef(zdict);
1774+
17451775
self->zst.opaque = NULL;
17461776
self->zst.zalloc = PyZlib_Malloc;
17471777
self->zst.zfree = PyZlib_Free;
1748-
self->zst.next_in = NULL;
1749-
self->zst.avail_in = 0;
1778+
17501779
self->unused_data = PyBytes_FromStringAndSize(NULL, 0);
17511780
if (self->unused_data == NULL) {
1752-
Py_CLEAR(self);
1753-
return NULL;
1781+
goto error;
17541782
}
17551783
self->lock = PyThread_allocate_lock();
17561784
if (self->lock == NULL) {
1757-
Py_DECREF(self);
17581785
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
1759-
return NULL;
1786+
goto error;
17601787
}
17611788
int err = inflateInit2(&(self->zst), wbits);
17621789
switch (err) {
17631790
case Z_OK:
17641791
self->is_initialised = 1;
17651792
if (self->zdict != NULL && wbits < 0) {
17661793
if (set_inflate_zdict_ZlibDecompressor(state, self) < 0) {
1767-
Py_DECREF(self);
1768-
return NULL;
1794+
goto error;
17691795
}
17701796
}
1771-
return (PyObject *)self;
1797+
break;
17721798
case Z_STREAM_ERROR:
1773-
Py_DECREF(self);
17741799
PyErr_SetString(PyExc_ValueError, "Invalid initialization option");
1775-
return NULL;
1800+
goto error;
17761801
case Z_MEM_ERROR:
1777-
Py_DECREF(self);
17781802
PyErr_SetString(PyExc_MemoryError,
17791803
"Can't allocate memory for decompression object");
1780-
return NULL;
1804+
goto error;
17811805
default:
17821806
zlib_error(state, self->zst, err, "while creating decompression object");
1783-
Py_DECREF(self);
1784-
return NULL;
1807+
goto error;
17851808
}
1809+
1810+
PyObject_GC_Track(self);
1811+
return (PyObject *)self;
1812+
1813+
error:
1814+
Py_DECREF(self);
1815+
return NULL;
17861816
}
17871817

17881818
#include "clinic/zlibmodule.c.h"
@@ -2015,19 +2045,25 @@ static PyMethodDef zlib_methods[] =
20152045

20162046
static PyType_Slot Comptype_slots[] = {
20172047
{Py_tp_dealloc, Comp_dealloc},
2048+
{Py_tp_traverse, compobject_traverse},
20182049
{Py_tp_methods, comp_methods},
20192050
{0, 0},
20202051
};
20212052

20222053
static PyType_Spec Comptype_spec = {
20232054
.name = "zlib.Compress",
20242055
.basicsize = sizeof(compobject),
2025-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
2056+
.flags = (
2057+
Py_TPFLAGS_DEFAULT
2058+
| Py_TPFLAGS_DISALLOW_INSTANTIATION
2059+
| Py_TPFLAGS_HAVE_GC
2060+
),
20262061
.slots= Comptype_slots,
20272062
};
20282063

20292064
static PyType_Slot Decomptype_slots[] = {
20302065
{Py_tp_dealloc, Decomp_dealloc},
2066+
{Py_tp_traverse, compobject_traverse},
20312067
{Py_tp_methods, Decomp_methods},
20322068
{Py_tp_members, Decomp_members},
20332069
{0, 0},
@@ -2036,12 +2072,17 @@ static PyType_Slot Decomptype_slots[] = {
20362072
static PyType_Spec Decomptype_spec = {
20372073
.name = "zlib.Decompress",
20382074
.basicsize = sizeof(compobject),
2039-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
2075+
.flags = (
2076+
Py_TPFLAGS_DEFAULT
2077+
| Py_TPFLAGS_DISALLOW_INSTANTIATION
2078+
| Py_TPFLAGS_HAVE_GC
2079+
),
20402080
.slots = Decomptype_slots,
20412081
};
20422082

20432083
static PyType_Slot ZlibDecompressor_type_slots[] = {
20442084
{Py_tp_dealloc, ZlibDecompressor_dealloc},
2085+
{Py_tp_traverse, ZlibDecompressor_traverse},
20452086
{Py_tp_members, ZlibDecompressor_members},
20462087
{Py_tp_new, zlib__ZlibDecompressor},
20472088
{Py_tp_doc, (char *)zlib__ZlibDecompressor__doc__},
@@ -2056,7 +2097,11 @@ static PyType_Spec ZlibDecompressor_type_spec = {
20562097
// ZlibDecompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
20572098
// which prevents to create a subclass.
20582099
// So calling PyType_GetModuleState() in this file is always safe.
2059-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
2100+
.flags = (
2101+
Py_TPFLAGS_DEFAULT
2102+
| Py_TPFLAGS_IMMUTABLETYPE
2103+
| Py_TPFLAGS_HAVE_GC
2104+
),
20602105
.slots = ZlibDecompressor_type_slots,
20612106
};
20622107

0 commit comments

Comments
 (0)