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
This commit is contained in:
Stéphane Wirtel 2017-06-10 14:36:57 +02:00 committed by Victor Stinner
parent 3c7b67bb34
commit 28288bebaf
1 changed files with 39 additions and 25 deletions

View File

@ -1353,6 +1353,30 @@ static PyMemberDef BZ2File_members[] = {
/* ===================================================================== */
/* 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 @@ BZ2File_init(BZ2FileObject *self, PyObject *args, PyObject *kwargs)
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 @@ BZ2File_init(BZ2FileObject *self, PyObject *args, PyObject *kwargs)
/* 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 @@ error:
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 @@ static PyTypeObject BZ2File_Type = {
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*/