bpo-23224: Fix segfaults and multiple leaks in the lzma and bz2 modules (GH-7822)

lzma.LZMADecompressor and bz2.BZ2Decompressor objects caused
segfaults when their `__init__()` methods were not called.

lzma.LZMADecompressor, lzma.LZMACompressor, bz2.BZ2Compressor,
and bz2.BZ2Decompressor objects would leak locks and internal buffers
when their `__init__()` methods were called multiple times.


https://bugs.python.org/issue23224
This commit is contained in:
Zackery Spytz 2023-02-23 06:00:58 -08:00 committed by GitHub
parent 9bba8035bd
commit 665730d217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 288 additions and 175 deletions

View File

@ -844,6 +844,10 @@ class BZ2DecompressorTest(BaseTest):
bzd.__init__() bzd.__init__()
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
def test_uninitialized_BZ2Decompressor_crash(self):
self.assertEqual(BZ2Decompressor.__new__(BZ2Decompressor).
decompress(bytes()), b'')
class CompressDecompressTest(BaseTest): class CompressDecompressTest(BaseTest):
def testCompress(self): def testCompress(self):

View File

@ -380,6 +380,10 @@ class CompressorDecompressorTestCase(unittest.TestCase):
lzd.__init__() lzd.__init__()
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) 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): class CompressDecompressFunctionTestCase(unittest.TestCase):

View File

@ -0,0 +1,6 @@
Fix segfaults when creating :class:`lzma.LZMADecompressor` and
:class:`bz2.BZ2Decompressor` objects without calling ``__init__()``, and fix
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.

View File

@ -15,6 +15,29 @@
#error "The maximum block size accepted by libbzip2 is UINT32_MAX." #error "The maximum block size accepted by libbzip2 is UINT32_MAX."
#endif #endif
typedef struct {
PyTypeObject *bz2_compressor_type;
PyTypeObject *bz2_decompressor_type;
} _bz2_state;
static inline _bz2_state *
get_module_state(PyObject *module)
{
void *state = PyModule_GetState(module);
assert(state != NULL);
return (_bz2_state *)state;
}
static struct PyModuleDef _bz2module;
static inline _bz2_state *
find_module_state_by_def(PyTypeObject *type)
{
PyObject *module = PyType_GetModuleByDef(type, &_bz2module);
assert(module != NULL);
return get_module_state(module);
}
/* On success, return value >= 0 /* On success, return value >= 0
On failure, return -1 */ On failure, return -1 */
static inline Py_ssize_t static inline Py_ssize_t
@ -214,12 +237,14 @@ error:
/*[clinic input] /*[clinic input]
module _bz2 module _bz2
class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type" class _bz2.BZ2Compressor "BZ2Compressor *" "clinic_state()->bz2_compressor_type"
class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type" class _bz2.BZ2Decompressor "BZ2Decompressor *" "clinic_state()->bz2_decompressor_type"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dc7d7992a79f9cb7]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=92348121632b94c4]*/
#define clinic_state() (find_module_state_by_def(type))
#include "clinic/_bz2module.c.h" #include "clinic/_bz2module.c.h"
#undef clinic_state
/*[clinic input] /*[clinic input]
_bz2.BZ2Compressor.compress _bz2.BZ2Compressor.compress
@ -295,24 +320,43 @@ BZ2_Free(void* ctx, void *ptr)
PyMem_RawFree(ptr); PyMem_RawFree(ptr);
} }
/*[clinic input]
@classmethod
_bz2.BZ2Compressor.__new__
/* Argument Clinic is not used since the Argument Clinic always want to compresslevel: int = 9
check the type which would be wrong here */ Compression level, as a number between 1 and 9.
static int /
_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
Create a compressor object for compressing data incrementally.
For one-shot compression, use the compress() function instead.
[clinic start generated code]*/
static PyObject *
_bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel)
/*[clinic end generated code: output=83346c96beaacad7 input=d4500d2a52c8b263]*/
{ {
int bzerror; int bzerror;
BZ2Compressor *self;
if (!(1 <= compresslevel && compresslevel <= 9)) { if (!(1 <= compresslevel && compresslevel <= 9)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"compresslevel must be between 1 and 9"); "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(); self->lock = PyThread_allocate_lock();
if (self->lock == NULL) { if (self->lock == NULL) {
Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1; return NULL;
} }
self->bzs.opaque = NULL; self->bzs.opaque = NULL;
@ -322,49 +366,11 @@ _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
if (catch_bz2_error(bzerror)) if (catch_bz2_error(bzerror))
goto error; goto error;
return 0; return (PyObject *)self;
error: error:
PyThread_free_lock(self->lock); Py_DECREF(self);
self->lock = NULL; return NULL;
return -1;
}
PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__,
"BZ2Compressor(compresslevel=9, /)\n"
"--\n"
"\n"
"Create a compressor object for compressing data incrementally.\n"
"\n"
" compresslevel\n"
" Compression level, as a number between 1 and 9.\n"
"\n"
"For one-shot compression, use the compress() function instead.");
static int
_bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{
int return_value = -1;
int compresslevel = 9;
if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) {
goto exit;
}
if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) {
goto exit;
}
if (PyTuple_GET_SIZE(args) < 1) {
goto skip_optional;
}
compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0));
if (compresslevel == -1 && PyErr_Occurred()) {
goto exit;
}
skip_optional:
return_value = _bz2_BZ2Compressor___init___impl((BZ2Compressor *)self, compresslevel);
exit:
return return_value;
} }
static void static void
@ -395,9 +401,8 @@ static PyMethodDef BZ2Compressor_methods[] = {
static PyType_Slot bz2_compressor_type_slots[] = { static PyType_Slot bz2_compressor_type_slots[] = {
{Py_tp_dealloc, BZ2Compressor_dealloc}, {Py_tp_dealloc, BZ2Compressor_dealloc},
{Py_tp_methods, BZ2Compressor_methods}, {Py_tp_methods, BZ2Compressor_methods},
{Py_tp_init, _bz2_BZ2Compressor___init__}, {Py_tp_new, _bz2_BZ2Compressor},
{Py_tp_new, PyType_GenericNew}, {Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__},
{Py_tp_doc, (char *)_bz2_BZ2Compressor___init____doc__},
{Py_tp_traverse, BZ2Compressor_traverse}, {Py_tp_traverse, BZ2Compressor_traverse},
{0, 0} {0, 0}
}; };
@ -624,28 +629,40 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data,
return result; return result;
} }
/* Argument Clinic is not used since the Argument Clinic always want to /*[clinic input]
check the type which would be wrong here */ @classmethod
static int _bz2.BZ2Decompressor.__new__
_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
Create a decompressor object for decompressing data incrementally.
For one-shot decompression, use the decompress() function instead.
[clinic start generated code]*/
static PyObject *
_bz2_BZ2Decompressor_impl(PyTypeObject *type)
/*[clinic end generated code: output=5150d51ccaab220e input=b87413ce51853528]*/
{ {
BZ2Decompressor *self;
int bzerror; int bzerror;
PyThread_type_lock lock = PyThread_allocate_lock(); assert(type != NULL && type->tp_alloc != NULL);
if (lock == NULL) { self = (BZ2Decompressor *)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"); PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1; return NULL;
} }
if (self->lock != NULL) {
PyThread_free_lock(self->lock);
}
self->lock = lock;
self->needs_input = 1; self->needs_input = 1;
self->bzs_avail_in_real = 0; self->bzs_avail_in_real = 0;
self->input_buffer = NULL; self->input_buffer = NULL;
self->input_buffer_size = 0; 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) if (self->unused_data == NULL)
goto error; goto error;
@ -653,40 +670,13 @@ _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
if (catch_bz2_error(bzerror)) if (catch_bz2_error(bzerror))
goto error; goto error;
return 0; return (PyObject *)self;
error: error:
Py_CLEAR(self->unused_data); Py_DECREF(self);
PyThread_free_lock(self->lock); return NULL;
self->lock = NULL;
return -1;
} }
static int
_bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{
int return_value = -1;
if (!_PyArg_NoPositional("BZ2Decompressor", args)) {
goto exit;
}
if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) {
goto exit;
}
return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self);
exit:
return return_value;
}
PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__,
"BZ2Decompressor()\n"
"--\n"
"\n"
"Create a decompressor object for decompressing data incrementally.\n"
"\n"
"For one-shot decompression, use the decompress() function instead.");
static void static void
BZ2Decompressor_dealloc(BZ2Decompressor *self) BZ2Decompressor_dealloc(BZ2Decompressor *self)
{ {
@ -738,10 +728,9 @@ static PyMemberDef BZ2Decompressor_members[] = {
static PyType_Slot bz2_decompressor_type_slots[] = { static PyType_Slot bz2_decompressor_type_slots[] = {
{Py_tp_dealloc, BZ2Decompressor_dealloc}, {Py_tp_dealloc, BZ2Decompressor_dealloc},
{Py_tp_methods, BZ2Decompressor_methods}, {Py_tp_methods, BZ2Decompressor_methods},
{Py_tp_init, _bz2_BZ2Decompressor___init__}, {Py_tp_doc, (char *)_bz2_BZ2Decompressor__doc__},
{Py_tp_doc, (char *)_bz2_BZ2Decompressor___init____doc__},
{Py_tp_members, BZ2Decompressor_members}, {Py_tp_members, BZ2Decompressor_members},
{Py_tp_new, PyType_GenericNew}, {Py_tp_new, _bz2_BZ2Decompressor},
{Py_tp_traverse, BZ2Decompressor_traverse}, {Py_tp_traverse, BZ2Decompressor_traverse},
{0, 0} {0, 0}
}; };
@ -762,31 +751,52 @@ static PyType_Spec bz2_decompressor_type_spec = {
static int static int
_bz2_exec(PyObject *module) _bz2_exec(PyObject *module)
{ {
PyTypeObject *bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, _bz2_state *state = get_module_state(module);
state->bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
&bz2_compressor_type_spec, NULL); &bz2_compressor_type_spec, NULL);
if (bz2_compressor_type == NULL) { if (state->bz2_compressor_type == NULL) {
return -1; return -1;
} }
int rc = PyModule_AddType(module, bz2_compressor_type); if (PyModule_AddType(module, state->bz2_compressor_type) < 0) {
Py_DECREF(bz2_compressor_type);
if (rc < 0) {
return -1; return -1;
} }
PyTypeObject *bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, state->bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
&bz2_decompressor_type_spec, NULL); &bz2_decompressor_type_spec, NULL);
if (bz2_decompressor_type == NULL) { if (state->bz2_decompressor_type == NULL) {
return -1; return -1;
} }
rc = PyModule_AddType(module, bz2_decompressor_type); if (PyModule_AddType(module, state->bz2_decompressor_type) < 0) {
Py_DECREF(bz2_decompressor_type);
if (rc < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
static int
_bz2_traverse(PyObject *module, visitproc visit, void *arg)
{
_bz2_state *state = get_module_state(module);
Py_VISIT(state->bz2_compressor_type);
Py_VISIT(state->bz2_decompressor_type);
return 0;
}
static int
_bz2_clear(PyObject *module)
{
_bz2_state *state = get_module_state(module);
Py_CLEAR(state->bz2_compressor_type);
Py_CLEAR(state->bz2_decompressor_type);
return 0;
}
static void
_bz2_free(void *module)
{
(void)_bz2_clear((PyObject *)module);
}
static struct PyModuleDef_Slot _bz2_slots[] = { static struct PyModuleDef_Slot _bz2_slots[] = {
{Py_mod_exec, _bz2_exec}, {Py_mod_exec, _bz2_exec},
{0, NULL} {0, NULL}
@ -795,6 +805,10 @@ static struct PyModuleDef_Slot _bz2_slots[] = {
static struct PyModuleDef _bz2module = { static struct PyModuleDef _bz2module = {
.m_base = PyModuleDef_HEAD_INIT, .m_base = PyModuleDef_HEAD_INIT,
.m_name = "_bz2", .m_name = "_bz2",
.m_size = sizeof(_bz2_state),
.m_traverse = _bz2_traverse,
.m_clear = _bz2_clear,
.m_free = _bz2_free,
.m_slots = _bz2_slots, .m_slots = _bz2_slots,
}; };

View File

@ -734,7 +734,8 @@ Compressor_init_raw(_lzma_state *state, lzma_stream *lzs, PyObject *filterspecs)
} }
/*[-clinic input] /*[-clinic input]
_lzma.LZMACompressor.__init__ @classmethod
_lzma.LZMACompressor.__new__
format: int(c_default="FORMAT_XZ") = FORMAT_XZ format: int(c_default="FORMAT_XZ") = FORMAT_XZ
The container format to use for the output. This can The container format to use for the output. This can
@ -765,8 +766,8 @@ the raw compressor does not support preset compression levels.
For one-shot compression, use the compress() function instead. For one-shot compression, use the compress() function instead.
[-clinic start generated code]*/ [-clinic start generated code]*/
static int static PyObject *
Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs) Compressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{ {
static char *arg_names[] = {"format", "check", "preset", "filters", NULL}; static char *arg_names[] = {"format", "check", "preset", "filters", NULL};
int format = FORMAT_XZ; int format = FORMAT_XZ;
@ -774,31 +775,37 @@ Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
uint32_t preset = LZMA_PRESET_DEFAULT; uint32_t preset = LZMA_PRESET_DEFAULT;
PyObject *preset_obj = Py_None; PyObject *preset_obj = Py_None;
PyObject *filterspecs = Py_None; PyObject *filterspecs = Py_None;
_lzma_state *state = PyType_GetModuleState(Py_TYPE(self)); Compressor *self;
_lzma_state *state = PyType_GetModuleState(type);
assert(state != NULL); assert(state != NULL);
if (!PyArg_ParseTupleAndKeywords(args, kwargs, if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"|iiOO:LZMACompressor", arg_names, "|iiOO:LZMACompressor", arg_names,
&format, &check, &preset_obj, &format, &check, &preset_obj,
&filterspecs)) { &filterspecs)) {
return -1; return NULL;
} }
if (format != FORMAT_XZ && check != -1 && check != LZMA_CHECK_NONE) { if (format != FORMAT_XZ && check != -1 && check != LZMA_CHECK_NONE) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Integrity checks are only supported by FORMAT_XZ"); "Integrity checks are only supported by FORMAT_XZ");
return -1; return NULL;
} }
if (preset_obj != Py_None && filterspecs != Py_None) { if (preset_obj != Py_None && filterspecs != Py_None) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Cannot specify both preset and filter chain"); "Cannot specify both preset and filter chain");
return -1; return NULL;
} }
if (preset_obj != Py_None) { if (preset_obj != Py_None && !uint32_converter(preset_obj, &preset)) {
if (!uint32_converter(preset_obj, &preset)) { return NULL;
return -1; }
}
assert(type != NULL && type->tp_alloc != NULL);
self = (Compressor *)type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
} }
self->alloc.opaque = NULL; self->alloc.opaque = NULL;
@ -808,8 +815,9 @@ Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
self->lock = PyThread_allocate_lock(); self->lock = PyThread_allocate_lock();
if (self->lock == NULL) { if (self->lock == NULL) {
Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1; return NULL;
} }
self->flushed = 0; self->flushed = 0;
@ -819,31 +827,33 @@ Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
check = LZMA_CHECK_CRC64; check = LZMA_CHECK_CRC64;
} }
if (Compressor_init_xz(state, &self->lzs, check, preset, filterspecs) != 0) { if (Compressor_init_xz(state, &self->lzs, check, preset, filterspecs) != 0) {
break; goto error;
} }
return 0; break;
case FORMAT_ALONE: case FORMAT_ALONE:
if (Compressor_init_alone(state, &self->lzs, preset, filterspecs) != 0) { if (Compressor_init_alone(state, &self->lzs, preset, filterspecs) != 0) {
break; goto error;
} }
return 0; break;
case FORMAT_RAW: case FORMAT_RAW:
if (Compressor_init_raw(state, &self->lzs, filterspecs) != 0) { if (Compressor_init_raw(state, &self->lzs, filterspecs) != 0) {
break; goto error;
} }
return 0; break;
default: default:
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Invalid container format: %d", format); "Invalid container format: %d", format);
break; goto error;
} }
PyThread_free_lock(self->lock); return (PyObject *)self;
self->lock = NULL;
return -1; error:
Py_DECREF(self);
return NULL;
} }
static void static void
@ -902,8 +912,7 @@ PyDoc_STRVAR(Compressor_doc,
static PyType_Slot lzma_compressor_type_slots[] = { static PyType_Slot lzma_compressor_type_slots[] = {
{Py_tp_dealloc, Compressor_dealloc}, {Py_tp_dealloc, Compressor_dealloc},
{Py_tp_methods, Compressor_methods}, {Py_tp_methods, Compressor_methods},
{Py_tp_init, Compressor_init}, {Py_tp_new, Compressor_new},
{Py_tp_new, PyType_GenericNew},
{Py_tp_doc, (char *)Compressor_doc}, {Py_tp_doc, (char *)Compressor_doc},
{Py_tp_traverse, Compressor_traverse}, {Py_tp_traverse, Compressor_traverse},
{0, 0} {0, 0}
@ -1165,7 +1174,8 @@ Decompressor_init_raw(_lzma_state *state, lzma_stream *lzs, PyObject *filterspec
} }
/*[clinic input] /*[clinic input]
_lzma.LZMADecompressor.__init__ @classmethod
_lzma.LZMADecompressor.__new__
format: int(c_default="FORMAT_AUTO") = FORMAT_AUTO format: int(c_default="FORMAT_AUTO") = FORMAT_AUTO
Specifies the container format of the input stream. If this is Specifies the container format of the input stream. If this is
@ -1189,54 +1199,57 @@ Create a decompressor object for decompressing data incrementally.
For one-shot decompression, use the decompress() function instead. For one-shot decompression, use the decompress() function instead.
[clinic start generated code]*/ [clinic start generated code]*/
static int static PyObject *
_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, _lzma_LZMADecompressor_impl(PyTypeObject *type, int format,
PyObject *memlimit, PyObject *filters) PyObject *memlimit, PyObject *filters)
/*[clinic end generated code: output=3e1821f8aa36564c input=81fe684a6c2f8a27]*/ /*[clinic end generated code: output=2d46d5e70f10bc7f input=ca40cd1cb1202b0d]*/
{ {
Decompressor *self;
const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK; const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK;
uint64_t memlimit_ = UINT64_MAX; uint64_t memlimit_ = UINT64_MAX;
lzma_ret lzret; lzma_ret lzret;
_lzma_state *state = PyType_GetModuleState(Py_TYPE(self)); _lzma_state *state = PyType_GetModuleState(type);
assert(state != NULL); assert(state != NULL);
if (memlimit != Py_None) { if (memlimit != Py_None) {
if (format == FORMAT_RAW) { if (format == FORMAT_RAW) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Cannot specify memory limit with FORMAT_RAW"); "Cannot specify memory limit with FORMAT_RAW");
return -1; return NULL;
} }
memlimit_ = PyLong_AsUnsignedLongLong(memlimit); memlimit_ = PyLong_AsUnsignedLongLong(memlimit);
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
return -1; return NULL;
} }
} }
if (format == FORMAT_RAW && filters == Py_None) { if (format == FORMAT_RAW && filters == Py_None) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Must specify filters for FORMAT_RAW"); "Must specify filters for FORMAT_RAW");
return -1; return NULL;
} else if (format != FORMAT_RAW && filters != Py_None) { } else if (format != FORMAT_RAW && filters != Py_None) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Cannot specify filters except with FORMAT_RAW"); "Cannot specify filters except with FORMAT_RAW");
return -1; return NULL;
} }
assert(type != NULL && type->tp_alloc != NULL);
self = (Decompressor *)type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
}
self->alloc.opaque = NULL; self->alloc.opaque = NULL;
self->alloc.alloc = PyLzma_Malloc; self->alloc.alloc = PyLzma_Malloc;
self->alloc.free = PyLzma_Free; self->alloc.free = PyLzma_Free;
self->lzs.allocator = &self->alloc; self->lzs.allocator = &self->alloc;
self->lzs.next_in = NULL; self->lzs.next_in = NULL;
PyThread_type_lock lock = PyThread_allocate_lock(); self->lock = PyThread_allocate_lock();
if (lock == NULL) { if (self->lock == NULL) {
Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
return -1; return NULL;
} }
if (self->lock != NULL) {
PyThread_free_lock(self->lock);
}
self->lock = lock;
self->check = LZMA_CHECK_UNKNOWN; self->check = LZMA_CHECK_UNKNOWN;
self->needs_input = 1; self->needs_input = 1;
@ -1251,43 +1264,43 @@ _lzma_LZMADecompressor___init___impl(Decompressor *self, int format,
case FORMAT_AUTO: case FORMAT_AUTO:
lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags); lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags);
if (catch_lzma_error(state, lzret)) { if (catch_lzma_error(state, lzret)) {
break; goto error;
} }
return 0; break;
case FORMAT_XZ: case FORMAT_XZ:
lzret = lzma_stream_decoder(&self->lzs, memlimit_, decoder_flags); lzret = lzma_stream_decoder(&self->lzs, memlimit_, decoder_flags);
if (catch_lzma_error(state, lzret)) { if (catch_lzma_error(state, lzret)) {
break; goto error;
} }
return 0; break;
case FORMAT_ALONE: case FORMAT_ALONE:
self->check = LZMA_CHECK_NONE; self->check = LZMA_CHECK_NONE;
lzret = lzma_alone_decoder(&self->lzs, memlimit_); lzret = lzma_alone_decoder(&self->lzs, memlimit_);
if (catch_lzma_error(state, lzret)) { if (catch_lzma_error(state, lzret)) {
break; goto error;
} }
return 0; break;
case FORMAT_RAW: case FORMAT_RAW:
self->check = LZMA_CHECK_NONE; self->check = LZMA_CHECK_NONE;
if (Decompressor_init_raw(state, &self->lzs, filters) == -1) { if (Decompressor_init_raw(state, &self->lzs, filters) == -1) {
break; goto error;
} }
return 0; break;
default: default:
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Invalid container format: %d", format); "Invalid container format: %d", format);
break; goto error;
} }
return (PyObject *)self;
error: error:
Py_CLEAR(self->unused_data); Py_DECREF(self);
PyThread_free_lock(self->lock); return NULL;
self->lock = NULL;
return -1;
} }
static void static void
@ -1345,9 +1358,8 @@ static PyMemberDef Decompressor_members[] = {
static PyType_Slot lzma_decompressor_type_slots[] = { static PyType_Slot lzma_decompressor_type_slots[] = {
{Py_tp_dealloc, Decompressor_dealloc}, {Py_tp_dealloc, Decompressor_dealloc},
{Py_tp_methods, Decompressor_methods}, {Py_tp_methods, Decompressor_methods},
{Py_tp_init, _lzma_LZMADecompressor___init__}, {Py_tp_new, _lzma_LZMADecompressor},
{Py_tp_new, PyType_GenericNew}, {Py_tp_doc, (char *)_lzma_LZMADecompressor__doc__},
{Py_tp_doc, (char *)_lzma_LZMADecompressor___init____doc__},
{Py_tp_traverse, Decompressor_traverse}, {Py_tp_traverse, Decompressor_traverse},
{Py_tp_members, Decompressor_members}, {Py_tp_members, Decompressor_members},
{0, 0} {0, 0}

View File

@ -71,6 +71,48 @@ _bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored))
return _bz2_BZ2Compressor_flush_impl(self); return _bz2_BZ2Compressor_flush_impl(self);
} }
PyDoc_STRVAR(_bz2_BZ2Compressor__doc__,
"BZ2Compressor(compresslevel=9, /)\n"
"--\n"
"\n"
"Create a compressor object for compressing data incrementally.\n"
"\n"
" compresslevel\n"
" Compression level, as a number between 1 and 9.\n"
"\n"
"For one-shot compression, use the compress() function instead.");
static PyObject *
_bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel);
static PyObject *
_bz2_BZ2Compressor(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
PyTypeObject *base_tp = clinic_state()->bz2_compressor_type;
int compresslevel = 9;
if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
!_PyArg_NoKeywords("BZ2Compressor", kwargs)) {
goto exit;
}
if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) {
goto exit;
}
if (PyTuple_GET_SIZE(args) < 1) {
goto skip_optional;
}
compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0));
if (compresslevel == -1 && PyErr_Occurred()) {
goto exit;
}
skip_optional:
return_value = _bz2_BZ2Compressor_impl(type, compresslevel);
exit:
return return_value;
}
PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__,
"decompress($self, /, data, max_length=-1)\n" "decompress($self, /, data, max_length=-1)\n"
"--\n" "--\n"
@ -168,4 +210,35 @@ exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=829bed4097cf2e63 input=a9049054013a1b77]*/
PyDoc_STRVAR(_bz2_BZ2Decompressor__doc__,
"BZ2Decompressor()\n"
"--\n"
"\n"
"Create a decompressor object for decompressing data incrementally.\n"
"\n"
"For one-shot decompression, use the decompress() function instead.");
static PyObject *
_bz2_BZ2Decompressor_impl(PyTypeObject *type);
static PyObject *
_bz2_BZ2Decompressor(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
PyTypeObject *base_tp = clinic_state()->bz2_decompressor_type;
if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
!_PyArg_NoPositional("BZ2Decompressor", args)) {
goto exit;
}
if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) {
goto exit;
}
return_value = _bz2_BZ2Decompressor_impl(type);
exit:
return return_value;
}
/*[clinic end generated code: output=805400e4805098ec input=a9049054013a1b77]*/

View File

@ -169,7 +169,7 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__, PyDoc_STRVAR(_lzma_LZMADecompressor__doc__,
"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" "LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n"
"--\n" "--\n"
"\n" "\n"
@ -192,14 +192,14 @@ PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__,
"\n" "\n"
"For one-shot decompression, use the decompress() function instead."); "For one-shot decompression, use the decompress() function instead.");
static int static PyObject *
_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, _lzma_LZMADecompressor_impl(PyTypeObject *type, int format,
PyObject *memlimit, PyObject *filters); PyObject *memlimit, PyObject *filters);
static int static PyObject *
_lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) _lzma_LZMADecompressor(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{ {
int return_value = -1; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 3 #define NUM_KEYWORDS 3
@ -257,7 +257,7 @@ _lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs
} }
filters = fastargs[2]; filters = fastargs[2];
skip_optional_pos: skip_optional_pos:
return_value = _lzma_LZMADecompressor___init___impl((Decompressor *)self, format, memlimit, filters); return_value = _lzma_LZMADecompressor_impl(type, format, memlimit, filters);
exit: exit:
return return_value; return return_value;
@ -338,4 +338,4 @@ exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=da3e83ba97244044 input=a9049054013a1b77]*/ /*[clinic end generated code: output=96c1fbdada1ef232 input=a9049054013a1b77]*/