diff -r a21a8943c59e -r b3a3bd124ae9 Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py Thu Dec 01 11:37:47 2016 -0500 +++ b/Lib/test/test_bz2.py Thu Dec 01 21:50:01 2016 -0500 @@ -102,6 +102,15 @@ self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=0) self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=10) + def test_uninitialized_object(self): + bz2c = BZ2Compressor.__new__(BZ2Compressor) + self.assertRaises(ValueError, bz2c.compress, b"foo") + self.assertRaises(ValueError, bz2c.flush) + + bz2d = BZ2Decompressor.__new__(BZ2Decompressor) + self.assertRaises(ValueError, bz2d.decompress, bytes()) + + def testRead(self): self.createTempFile() with BZ2File(self.filename) as bz2f: diff -r a21a8943c59e -r b3a3bd124ae9 Lib/test/test_lzma.py --- a/Lib/test/test_lzma.py Thu Dec 01 11:37:47 2016 -0500 +++ b/Lib/test/test_lzma.py Thu Dec 01 21:50:01 2016 -0500 @@ -58,6 +58,14 @@ lzd.decompress(empty) self.assertRaises(EOFError, lzd.decompress, b"quux") + def test_uninitialized_object(self): + lzc = LZMACompressor.__new__(LZMACompressor) + self.assertRaises(LZMAError, lzc.compress, b"foo") + self.assertRaises(LZMAError, lzc.flush) + + lzd = LZMADecompressor.__new__(LZMADecompressor) + self.assertRaises(LZMAError, lzd.decompress, bytes()) + def test_bad_filter_spec(self): self.assertRaises(TypeError, LZMACompressor, filters=[b"wobsite"]) self.assertRaises(ValueError, LZMACompressor, filters=[{"xyzzy": 3}]) diff -r a21a8943c59e -r b3a3bd124ae9 Modules/_bz2module.c --- a/Modules/_bz2module.c Thu Dec 01 11:37:47 2016 -0500 +++ b/Modules/_bz2module.c Thu Dec 01 21:50:01 2016 -0500 @@ -9,6 +9,7 @@ #include "pythread.h" #endif +#include "_compress.h" #include #include @@ -44,6 +45,7 @@ #ifdef WITH_THREAD PyThread_type_lock lock; #endif + int initialized; } BZ2Compressor; typedef struct { @@ -62,6 +64,7 @@ #ifdef WITH_THREAD PyThread_type_lock lock; #endif + int initialized; } BZ2Decompressor; static PyTypeObject BZ2Compressor_Type; @@ -237,6 +240,7 @@ _bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data) /*[clinic end generated code: output=59365426e941fbcc input=85c963218070fc4c]*/ { + CHECK_INIT(self, "BZ2Compressor", PyExc_ValueError) PyObject *result = NULL; ACQUIRE_LOCK(self); @@ -262,6 +266,7 @@ _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) /*[clinic end generated code: output=3ef03fc1b092a701 input=d64405d3c6f76691]*/ { + CHECK_INIT(self, "BZ2Compressor", PyExc_ValueError) PyObject *result = NULL; ACQUIRE_LOCK(self); @@ -339,6 +344,7 @@ bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0); if (catch_bz2_error(bzerror)) goto error; + self->initialized = 1; return 0; @@ -618,6 +624,7 @@ Py_ssize_t max_length) /*[clinic end generated code: output=23e41045deb240a3 input=52e1ffc66a8ea624]*/ { + CHECK_INIT(self, "BZ2Decompressor", PyExc_ValueError) PyObject *result = NULL; ACQUIRE_LOCK(self); @@ -670,6 +677,7 @@ bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); if (catch_bz2_error(bzerror)) goto error; + self->initialized = 1; return 0; diff -r a21a8943c59e -r b3a3bd124ae9 Modules/_compress.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/_compress.h Thu Dec 01 21:50:01 2016 -0500 @@ -0,0 +1,19 @@ +/* + * Macros shared between lzma and bz2 modukes + */ + +/* + * Check that the compressor/decompressor's __init__ method was called (issue23224). + * This avoids a segfault if a compressor/decompressor is created by manually + * calling __new__ and then left uninitialized, or if a subclass doesn't call + * super() in an overriden __init_- mwthod. + * + * Since the lzma_allocator struct's alloc function is always set by us during + * proper initialization, checking it is sufficient to determine whether + * initialization occured. + */ +#define CHECK_INIT(self, name, error) if (self->initialized == 0) { \ + PyErr_Format(error, "%s.__init__() was not called by %s.__init__()", name, Py_TYPE(self)->tp_name); \ + return NULL; \ + } + diff -r a21a8943c59e -r b3a3bd124ae9 Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c Thu Dec 01 11:37:47 2016 -0500 +++ b/Modules/_lzmamodule.c Thu Dec 01 21:50:01 2016 -0500 @@ -9,6 +9,7 @@ #include "Python.h" #include "structmember.h" +#include "_compress.h" #ifdef WITH_THREAD #include "pythread.h" #endif @@ -51,6 +52,7 @@ #ifdef WITH_THREAD PyThread_type_lock lock; #endif + int initialized; } Compressor; typedef struct { @@ -66,6 +68,7 @@ #ifdef WITH_THREAD PyThread_type_lock lock; #endif + int initialized; } Decompressor; /* LZMAError class object. */ @@ -564,6 +567,7 @@ _lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data) /*[clinic end generated code: output=31f615136963e00f input=64019eac7f2cc8d0]*/ { + CHECK_INIT(self, "LZMACompressor", Error) PyObject *result = NULL; ACQUIRE_LOCK(self); @@ -589,6 +593,7 @@ _lzma_LZMACompressor_flush_impl(Compressor *self) /*[clinic end generated code: output=fec21f3e22504f50 input=6b369303f67ad0a8]*/ { + CHECK_INIT(self, "LZMACompressor", Error) PyObject *result = NULL; ACQUIRE_LOCK(self); @@ -765,6 +770,8 @@ } #endif + self->initialized = 1; + self->flushed = 0; switch (format) { case FORMAT_XZ: @@ -1084,6 +1091,7 @@ Py_ssize_t max_length) /*[clinic end generated code: output=ef4e20ec7122241d input=60c1f135820e309d]*/ { + CHECK_INIT(self, "LZMADecompressor", Error) PyObject *result = NULL; ACQUIRE_LOCK(self); @@ -1196,6 +1204,8 @@ if (self->unused_data == NULL) goto error; + self->initialized = 1; + switch (format) { case FORMAT_AUTO: lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags);