Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Lib/test/test_bz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,10 @@ def test_refleaks_in___init__(self):
bzd.__init__()
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)

def test_uninitialized_BZ2Decompressor_crash(self):
Comment thread
ZackerySpytz marked this conversation as resolved.
self.assertEqual(BZ2Decompressor.__new__(BZ2Decompressor).
decompress(bytes()), b'')


class CompressDecompressTest(BaseTest):
def testCompress(self):
Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_lzma.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ def test_refleaks_in_decompressor___init__(self):
lzd.__init__()
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)

def test_uninitialized_LZMADecompressor_crash(self):
self.assertEqual(LZMADecompressor.__new__(LZMADecompressor).
decompress(bytes()), b'')


class CompressDecompressFunctionTestCase(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fix segfaults when creating :class:`lzma.LZMADecompressor` and
:class:`bz2.BZ2Decompressor` objects without calling ``__init__()``, and fix
Comment thread
erlend-aasland marked this conversation as resolved.
leakage of locks and internal buffers when calling the ``__init__()``
methods of :class:`lzma.LZMADecompressor`, :class:`lzma.LZMACompressor`,
:class:`bz2.BZ2Compressor`, and :class:`bz2.BZ2Decompressor` objects
multiple times.
77 changes: 44 additions & 33 deletions Modules/_bz2module.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ BZ2_Free(void* ctx, void *ptr)
}

/*[clinic input]
_bz2.BZ2Compressor.__init__
@classmethod
_bz2.BZ2Compressor.__new__

compresslevel: int = 9
Compression level, as a number between 1 and 9.
Expand All @@ -294,22 +295,30 @@ Create a compressor object for compressing data incrementally.
For one-shot compression, use the compress() function instead.
[clinic start generated code]*/

static int
_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
/*[clinic end generated code: output=c4e6adfd02963827 input=4e1ff7b8394b6e9a]*/
static PyObject *
_bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel)
/*[clinic end generated code: output=83346c96beaacad7 input=d4500d2a52c8b263]*/
{
int bzerror;
BZ2Compressor *self;

if (!(1 <= compresslevel && compresslevel <= 9)) {
PyErr_SetString(PyExc_ValueError,
"compresslevel must be between 1 and 9");
return -1;
return NULL;
}

assert(type != NULL && type->tp_alloc != NULL);
self = (BZ2Compressor *)type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
}

self->lock = PyThread_allocate_lock();
if (self->lock == NULL) {
Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1;
return NULL;
}

self->bzs.opaque = NULL;
Expand All @@ -319,12 +328,11 @@ _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
if (catch_bz2_error(bzerror))
goto error;

return 0;
return (PyObject *)self;

error:
PyThread_free_lock(self->lock);
self->lock = NULL;
return -1;
Py_DECREF(self);
return NULL;
}

static void
Expand Down Expand Up @@ -364,7 +372,7 @@ static PyTypeObject BZ2Compressor_Type = {
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
_bz2_BZ2Compressor___init____doc__, /* tp_doc */
_bz2_BZ2Compressor__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
Expand All @@ -379,9 +387,9 @@ static PyTypeObject BZ2Compressor_Type = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
_bz2_BZ2Compressor___init__, /* tp_init */
0, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
_bz2_BZ2Compressor, /* tp_new */
};


Expand Down Expand Up @@ -604,48 +612,51 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data,
}

/*[clinic input]
_bz2.BZ2Decompressor.__init__
@classmethod
_bz2.BZ2Decompressor.__new__

Create a decompressor object for decompressing data incrementally.

For one-shot decompression, use the decompress() function instead.
[clinic start generated code]*/

static int
_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
/*[clinic end generated code: output=e4d2b9bb866ab8f1 input=95f6500dcda60088]*/
static PyObject *
_bz2_BZ2Decompressor_impl(PyTypeObject *type)
/*[clinic end generated code: output=5150d51ccaab220e input=b87413ce51853528]*/
{
BZ2Decompressor *self;
int bzerror;

PyThread_type_lock lock = PyThread_allocate_lock();
if (lock == NULL) {
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1;
assert(type != NULL && type->tp_alloc != NULL);
self = (BZ2Decompressor *)type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
}
if (self->lock != NULL) {
PyThread_free_lock(self->lock);

self->lock = PyThread_allocate_lock();
if (self->lock == NULL) {
Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return NULL;
}
self->lock = lock;

self->needs_input = 1;
self->bzs_avail_in_real = 0;
self->input_buffer = NULL;
self->input_buffer_size = 0;
Py_XSETREF(self->unused_data, PyBytes_FromStringAndSize(NULL, 0));
self->unused_data = PyBytes_FromStringAndSize(NULL, 0);
if (self->unused_data == NULL)
goto error;

bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
if (catch_bz2_error(bzerror))
goto error;

return 0;
return (PyObject *)self;

error:
Py_CLEAR(self->unused_data);
PyThread_free_lock(self->lock);
self->lock = NULL;
return -1;
Py_DECREF(self);
return NULL;
}

static void
Expand Down Expand Up @@ -705,7 +716,7 @@ static PyTypeObject BZ2Decompressor_Type = {
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
_bz2_BZ2Decompressor___init____doc__, /* tp_doc */
_bz2_BZ2Decompressor__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
Expand All @@ -720,9 +731,9 @@ static PyTypeObject BZ2Decompressor_Type = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
_bz2_BZ2Decompressor___init__, /* tp_init */
0, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
_bz2_BZ2Decompressor, /* tp_new */
};


Expand Down
Loading