bpo-30614: testInitNonExistentFile() of test_bz2 leaks references (#2033)
* bpo-30614: testInitNonExistentFile() of test_bz2 leaks references
Extract the code of BZ2File_dealloc and create a new BZ2File_clear()
function. Call BZ2File_clear() in BZ2File_dealloc().
Define BZ2File_clear() as tp_clear.
Move the lock initialization before the "self->file =
PyObject_CallFunction" in BZ2File_init() and check the lock is not
created twice.
Call BZ2File_clear() in BZ2File_init() after the init of the lock
Co-Authored-By: Victor Stinner <victor.stinner@gmail.com>
* Create bz2module.c
Fix after the review of Victor Stinner
diff --git a/Modules/bz2module.c b/Modules/bz2module.c
index fe417c5..81f1688 100644
--- a/Modules/bz2module.c
+++ b/Modules/bz2module.c
@@ -1353,6 +1353,30 @@
/* ===================================================================== */
/* Slot definitions for BZ2File_Type. */
+static int
+BZ2File_clear(BZ2FileObject *self)
+{
+ int bzerror;
+
+ ACQUIRE_LOCK(self);
+ switch (self->mode) {
+ case MODE_READ:
+ case MODE_READ_EOF:
+ BZ2_bzReadClose(&bzerror, self->fp);
+ break;
+ case MODE_WRITE:
+ BZ2_bzWriteClose(&bzerror, self->fp,
+ 0, NULL, NULL);
+ break;
+ }
+ if (self->fp != NULL && self->file != NULL)
+ PyFile_DecUseCount((PyFileObject *)self->file);
+ self->fp = NULL;
+ Util_DropReadAhead(self);
+ Py_CLEAR(self->file);
+ RELEASE_LOCK(self);
+ return 0;
+}
static int
BZ2File_init(BZ2FileObject *self, PyObject *args, PyObject *kwargs)
@@ -1420,6 +1444,19 @@
mode = (mode_char == 'r') ? "rb" : "wb";
+#ifdef WITH_THREAD
+ if (!self->lock) {
+ self->lock = PyThread_allocate_lock();
+ }
+
+ if (!self->lock) {
+ PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
+ goto error;
+ }
+#endif
+
+ BZ2File_clear(self);
+
self->file = PyObject_CallFunction((PyObject*)&PyFile_Type, "(Osi)",
name, mode, buffering);
if (self->file == NULL)
@@ -1428,14 +1465,6 @@
/* From now on, we have stuff to dealloc, so jump to error label
* instead of returning */
-#ifdef WITH_THREAD
- self->lock = PyThread_allocate_lock();
- if (!self->lock) {
- PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
- goto error;
- }
-#endif
-
if (mode_char == 'r')
self->fp = BZ2_bzReadOpen(&bzerror,
PyFile_AsFile(self->file),
@@ -1469,26 +1498,11 @@
static void
BZ2File_dealloc(BZ2FileObject *self)
{
- int bzerror;
+ BZ2File_clear(self);
#ifdef WITH_THREAD
if (self->lock)
PyThread_free_lock(self->lock);
#endif
- switch (self->mode) {
- case MODE_READ:
- case MODE_READ_EOF:
- BZ2_bzReadClose(&bzerror, self->fp);
- break;
- case MODE_WRITE:
- BZ2_bzWriteClose(&bzerror, self->fp,
- 0, NULL, NULL);
- break;
- }
- if (self->fp != NULL && self->file != NULL)
- PyFile_DecUseCount((PyFileObject *)self->file);
- self->fp = NULL;
- Util_DropReadAhead(self);
- Py_XDECREF(self->file);
Py_TYPE(self)->tp_free((PyObject *)self);
}
@@ -1574,7 +1588,7 @@
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
BZ2File__doc__, /*tp_doc*/
0, /*tp_traverse*/
- 0, /*tp_clear*/
+ (inquiry)BZ2File_clear, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
(getiterfunc)BZ2File_getiter, /*tp_iter*/